v08i070: Smail release 2.3, Part04/05

sources-request at mirror.UUCP sources-request at mirror.UUCP
Wed Feb 18 11:32:45 AEST 1987


Submitted by:  Larry Auton <lda at clyde.att.com>
Mod.sources: Volume 8, Issue 70
Archive-name: smail2/Part04

[ OOPS!  Please excuse the "Part03/03" header on the last part.  --r$ ]

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of shell archive."
# Contents:  src/deliver.c src/headers.c src/main.c src/make.cf.sh
#   src/map.c src/misc.c src/resolve.c src/smail.prompt
#   src/svbinmail.c src/sysexits.h
# Wrapped by rs at mirror on Mon Feb  9 17:10:08 1987
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'src/deliver.c'" '(11313 characters)'
if test -f 'src/deliver.c' ; then 
  echo shar: will not over-write existing file "'src/deliver.c'"
else
sed 's/^X//' >src/deliver.c <<'@//E*O*F src/deliver.c//'
X/*
X**  Deliver.c
X**
X**  Routines to effect delivery of mail for rmail/smail. 
X**
X*/
X
X#ifndef lint
Xstatic char 	*sccsid="@(#)deliver.c	2.3 (smail) 1/26/87";
X#endif
X
X# include	<stdio.h>
X# include	<sys/types.h>
X# include	<ctype.h>
X# include	"defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int  exitstat;		/* set if a forked mailer fails */
Xextern enum edebug debug;	/* how verbose we are 		*/ 
Xextern char hostname[];		/* our uucp hostname 		*/
Xextern char hostdomain[];	/* our host's domain 		*/
Xextern enum ehandle handle;	/* what we handle		*/
Xextern enum erouting routing;	/* how we're routing addresses  */
Xextern char *uuxargs;		/* arguments given to uux       */
Xextern int  queuecost;		/* threshold for queueing mail  */
Xextern int  maxnoqueue;		/* max number of uucico's       */
Xextern char *spoolfile;		/* file name of spooled message */
Xextern FILE *spoolfp;		/* file ptr  to spooled message */
Xextern int spoolmaster;		/* set if creator of spoolfile  */
Xextern char nows[];		/* local time in ctime(3) format*/
Xextern char arpanows[];		/* local time in arpadate format*/
Xchar stderrfile[20];		/* error file for stderr traping*/
X
X/*
X**
X**  deliver():  hand the letter to the proper mail programs.
X**
X**  Issues one command for each different host of <hostv>,
X**  constructing the proper command for LOCAL or UUCP mail.
X**  Note that LOCAL mail has blank host names.
X**
X**  The <userv> names for each host are arguments to the command.
X** 
X**  Prepends a "From" line to the letter just before going 
X**  out, with a "remote from <hostname>" if it is a UUCP letter.
X**
X*/
X
Xdeliver(argc, hostv, userv, formv, costv)
Xint argc;				/* number of addresses		*/
Xchar *hostv[];				/* host names			*/
Xchar *userv[];				/* user names			*/
Xenum eform formv[];			/* form for each address	*/
Xint costv[];				/* cost vector 			*/
X{
X	FILE *out;			/* pipe to mailer		*/
X	FILE *popen();			/* to fork a mailer 		*/
X#ifdef RECORD
X	void record();			/* record all transactions	*/
X#endif
X#ifdef LOG
X	void log();
X#endif
X	char *mktemp();
X	char from[SMLBUF];		/* accumulated from argument 	*/
X	char lcommand[SMLBUF];		/* local command issued 	*/
X	char rcommand[SMLBUF];		/* remote command issued	*/
X	char scommand[SMLBUF];		/* retry  command issued	*/
X	char *command;			/* actual command		*/
X	char buf[SMLBUF];		/* copying rest of the letter   */
X	enum eform form;		/* holds form[i] for speed 	*/
X	long size;			/* number of bytes of message 	*/
X	char *flags;			/* flags for uux		*/
X	char *sflag;			/* flag  for smail		*/
X	int i, j, stat, retrying;
X	char *c, *postmaster();
X	int failcount = 0;
X	int noqcnt = 0;			/* number of uucico's started   */
X	char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately    */
X	char *uux_queue   = UUX_QUEUE;	/* uucico job gets queued       */
X	off_t message;
X
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X	(void) fseek(spoolfp, 0L, 0);
X	(void) fgets(from, sizeof(from), spoolfp);
X	if((c = index(from, '\n')) != 0) *c = '\0';
X	message = ftell(spoolfp);
X
X/*
X**  We pass through the list of addresses.
X*/
X	stderrfile[0] = '\0';
X	for(i = 0; i < argc; i++) {
X		char *lend = lcommand;
X		char *rend = rcommand;
X		char *send = scommand;
X
X/*
X**  If we don't have sendmail, arrange to trap standard error
X**  for inclusion in the message that is returned with failed mail.
X*/
X		(void) unlink(stderrfile);
X		(void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
X		(void) mktemp(stderrfile);
X		(void) freopen(stderrfile, "w", stderr);
X
X		*lend = *rend = *send = '\0';
X
X/*
X**  If form == ERROR, the address was bad 
X**  If form == SENT, it has been sent on a  previous pass.
X*/
X		form = formv[i];
X		if (form == SENT) {
X			continue;
X		}
X/*
X**  Build the command based on whether this is local mail or uucp mail.
X**  By default, don't allow more than 'maxnoqueue' uucico commands to
X**  be started by a single invocation of 'smail'.
X*/
X		if(uuxargs == NULL) {	/* flags not set on command line */
X			if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
X				flags = uux_noqueue;
X			} else {
X				flags = uux_queue;
X			}
X		} else {
X			flags = uuxargs;
X		}
X
X		retrying = 0;
X		if(routing == JUSTDOMAIN) {
X			sflag = "-r";
X		} else if(routing == ALWAYS) {
X			sflag = "-R";
X		} else {
X			sflag = "";
X		}
X
X		(void) sprintf(lcommand, LMAIL(from, hostv[i]));
X		(void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
X
X/*
X**  For each address with the same host name and form, append the user
X**  name to the command line, and set form = ERROR so we skip this address
X**  on later passes. 
X*/
X		/* we initialized lend (rend) to point at the
X		 * beginning of its buffer, so that at
X		 * least one address will be used regardless
X		 * of the length of lcommand (rcommand).
X		 */
X		for (j = i; j < argc; j++) {
X			if ((formv[j] != form)
X			 || (strcmpic(hostv[i], hostv[j]) != 0)
X			 || ((lend - lcommand) > MAXCLEN)
X			 || ((rend - rcommand) > MAXCLEN)) {
X				continue;
X			}
X
X			/*
X			** seek to the end of scommand
X			** and add on a 'smail' command
X			** multiple commands are separated by ';'
X			*/
X
X			send += strlen(send);
X			if(send != scommand) {
X				*send++ = ';' ;
X			}
X
X			(void) sprintf(send, RETRY(sflag));
X			send += strlen(send);
X
X			lend += strlen(lend);
X			rend += strlen(rend);
X
X			if (form == LOCAL) {
X				(void) sprintf(lend, LARG(userv[j]));
X				(void) sprintf(send, LARG(userv[j]));
X			} else {
X				(void) sprintf(lend, RLARG(hostv[i], userv[j]));
X				(void) sprintf(send, RLARG(hostv[i], userv[j]));
X			}
X
X			(void) sprintf(rend, RARG(userv[j]));
X			formv[j] = SENT;
X		}
Xretry:
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X		(void) fseek(spoolfp, message, 0);
X
X		/* if the address was in a bogus form (usually DOMAIN),
X		** then don't bother trying the uux.
X		**
X		** Rather, go straight to the next smail routing level.
X		*/
X		if(form == ERROR) {
X			static char errbuf[SMLBUF];
X			(void) sprintf(errbuf,
X				"address resolution ('%s' @ '%s') failed",
X					userv[i], hostv[i]);
X			command = errbuf;
X			size    = 0;
X			goto form_error;
X		}
X
X		if (retrying) {
X			command = scommand;
X		} else if (form == LOCAL) {
X			command = lcommand;
X		} else {
X			command = rcommand;
X			if(flags == uux_noqueue) {
X				noqcnt++;
X			}
X		}
X		ADVISE("COMMAND: %s\n", command);
X
X/*
X** Fork the mailer and set it up for writing so we can send the mail to it,
X** or for debugging divert the output to stdout.
X*/
X		if (debug == YES) {
X			out = stdout;
X		} else {
X			failcount = 0;
X			do {
X				out = popen(command, "w");
X				if (out) break;
X				/*
X				 * Fork failed.  System probably overloaded.
X				 * Wait awhile and try again 10 times.
X				 * If it keeps failing, probably some
X				 * other problem, like no uux or smail.
X				 */
X				(void) sleep(60);
X			} while (++failcount < 10);
X		}
X		if(out == NULL) {
X			exitstat = EX_UNAVAILABLE;
X			(void) printf("couldn't execute %s.\n", command);
X			continue;
X		}
X
X		size = 0;
X/*
X**  Output our From_ line.
X*/
X		if (form == LOCAL) {
X#ifdef SENDMAIL
X			size += fprintf(out, LFROM(from, nows, hostname));
X#else
X			char *p;
X			if((p=index(from, '!')) == NULL) {
X				size += fprintf(out,
X					LFROM(from, nows, hostname));
X			} else {
X				*p = NULL;
X				size += fprintf(out, RFROM(p+1, nows, from));
X				*p = '!';
X			}
X#endif
X		} else {
X			size += fprintf(out, RFROM(from, nows, hostname));
X		}
X
X#ifdef SENDMAIL
X/*
X**  If using sendmail, insert a Received: line only for mail
X**  that is being passed to uux.  If not using sendmail, always
X**  insert the received line, since sendmail isn't there to do it.
X*/
X		if(command == rcommand && handle != ALL)
X#endif
X		{
X			size += fprintf(out,
X				"Received: by %s (%s)\n\tid AA%05d; %s\n",
X					hostdomain, VERSION,
X					getpid(), arpanows);
X		}
X
X/*
X**  Copy input.
X*/
X		while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X			size += fputs(buf, out);
X		}
X/*
X**  Get exit status and if non-zero, set global exitstat so when we exit
X**  we can indicate an error.
X*/
Xform_error:
X		if (debug != YES) {
X			if(form == ERROR) {
X				exitstat = EX_NOHOST;
X			} else if (stat = pclose(out)) {
X				exitstat = stat >> 8;
X			}
X			/*
X			 * The 'retrying' check prevents a smail loop.
X			 */
X			if(exitstat != 0) {
X				/*
X				** the mail failed, probably because the host
X				** being uux'ed isn't in L.sys or local user
X				** is unknown.
X				*/
X
X				if((retrying == 0)	/* first pass */
X				&& (routing != REROUTE)	/* have higher level */
X				&& (form != LOCAL)) {	/* can't route local */
X					/*
X					** Try again using a higher
X					** level of routing.
X					*/
X					ADVISE("%s failed (%d)\ntrying %s\n",
X						command, exitstat, scommand);
X					exitstat = 0;
X					retrying = 1;
X					form = SENT;
X					goto retry;
X				}
X
X				/*
X				** if we have no other routing possibilities
X				** see that the mail is returned to sender.
X				*/
X
X				if((routing == REROUTE)
X			        || (form == LOCAL)) {
X
X					/*
X					** if this was our last chance,
X					** return the mail to the sender.
X					*/
X
X					ADVISE("%s failed (%d)\n",
X						command, exitstat);
X					
X					(void) fseek(spoolfp, message, 0);
X#ifdef SENDMAIL
X					/* if we have sendmail, then it
X					** was handed the mail, which failed.
X					** sendmail returns the failed mail
X					** for us, so we need not do it again.
X					*/
X					if(form != LOCAL)
X#endif
X					{
X						return_mail(from, command);
X					}
X					exitstat = 0;
X				}
X			}
X# ifdef LOG
X			else {
X				if(retrying == 0) log(command, from, size); /* */
X			}
X# endif
X		}
X	}
X/*
X**  Update logs and records.
X*/
X# ifdef RECORD
X	(void) fseek(spoolfp, message, 0);
X	record(command, from, size);
X# endif
X
X/*
X**  close spool file pointer.
X**  if we created it, then unlink file.
X*/
X	(void) fclose(spoolfp);
X	if(spoolmaster) {
X		(void) unlink(spoolfile);
X	}
X	(void) unlink(stderrfile);
X}
X
X/*
X** return mail to sender, as determined by From_ line.
X*/
Xreturn_mail(from, fcommand)
Xchar *from, *fcommand;
X{
X	char buf[SMLBUF];
X	char domain[SMLBUF], user[SMLBUF];
X	char *r;
X	FILE *fp, *out, *popen();
X	int i = 0;
X
X	r = buf;
X
X	(void) sprintf(r, "%s %s", SMAIL, VFLAG);
X	r += strlen(r);
X
X	if(islocal(from, domain, user)) {
X		(void) sprintf(r, LARG(user));
X	} else {
X		(void) sprintf(r, RLARG(domain, user));
X	}
X
X	i = 0;
X	do {
X		out = popen(buf, "w");
X		if (out) break;
X		/*
X		 * Fork failed.  System probably overloaded.
X		 * Wait awhile and try again 10 times.
X		 * If it keeps failing, probably some
X		 * other problem, like no uux or smail.
X		 */
X		(void) sleep(60);
X	} while (++i < 10);
X
X	if(out == NULL) {
X		(void) printf("couldn't execute %s.\n", buf);
X		return;
X	}
X
X	(void) fprintf(out, "Date: %s\n", arpanows);
X	(void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
X	(void) fprintf(out, "Subject: failed mail\n");
X	(void) fprintf(out, "To: %s\n", from);
X	(void) fprintf(out, "\n");
X	(void) fprintf(out, "=======     command failed      =======\n\n");
X	(void) fprintf(out, " COMMAND: %s\n\n", fcommand);
X
X	(void) fprintf(out, "======= standard error follows  =======\n");
X	(void) fflush(stderr);
X	if((fp = fopen(stderrfile, "r")) != NULL) {
X		while(fgets(buf, sizeof(buf), fp) != NULL) {
X			(void) fputs(buf, out);
X		}
X	}
X	(void) fclose(fp);
X	(void) fprintf(out, "======= text of message follows =======\n");
X/*
X**  Copy input.
X*/
X	(void) fprintf(out, "From %s\n", from);
X	while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X		(void) fputs(buf, out);
X	}
X	(void) pclose(out);
X}
@//E*O*F src/deliver.c//
if test 11313 -ne "`wc -c <'src/deliver.c'`"; then
    echo shar: error transmitting "'src/deliver.c'" '(should have been 11313 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/headers.c'" '(13909 characters)'
if test -f 'src/headers.c' ; then 
  echo shar: will not over-write existing file "'src/headers.c'"
else
sed 's/^X//' >src/headers.c <<'@//E*O*F src/headers.c//'
X/*
X**  message spooing, header and address parsing and completion
X**  functions for smail/rmail
X*/
X
X#ifndef lint
Xstatic char 	*sccsid="@(#)headers.c	2.3 (smail) 1/26/87";
X#endif
X
X# include	<stdio.h>
X# include	<sys/types.h>
X# include	<time.h>
X# include	<ctype.h>
X# include	<pwd.h>
X# include	"defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern enum edebug debug;	/* how verbose we are 		*/ 
Xextern char hostname[];		/* */
Xextern char hostdomain[];	/* */
Xextern char *spoolfile;		/* file name of spooled message */
Xextern FILE *spoolfp;		/* file ptr  to spooled message */
Xextern int spoolmaster;		/* set if creator of spoolfile  */
Xextern time_t now;		/* time				*/
Xextern char nows[], arpanows[];	/* time strings			*/
Xextern struct tm *gmt, *loc;	/* time structs			*/
X
Xstatic char toline[SMLBUF];
Xstatic char fromline[SMLBUF];
Xstatic char dateline[SMLBUF];
Xstatic char midline[SMLBUF];
Xstatic char *ieof = "NOTNULL";
X
Xstruct reqheaders {
X	char *name;
X	char *field;
X	char have;
X};
X
Xstatic struct reqheaders reqtab[] = {
X	"Date:"		,	dateline	,	'N'	,
X	"From:"		,	fromline	,	'N'	,
X	"Message-Id:"	,	midline		,	'N'	,
X	"To:"		,	toline		,	'N'	,
X	NULL 		,	NULL		,	'N'
X};
X
X
X/*
X**
X** parse(): parse <address> into <domain, user, form>.
X**
X** 	input		form
X**	-----		----
X**	user		LOCAL
X**	domain!user	DOMAIN
X**	user at domain	DOMAIN
X**	@domain,address	LOCAL	(just for sendmail)
X**	host!address	UUCP
X**
X*/
X
Xenum eform
Xparse(address, domain, user)
Xchar *address;		/* input address 	*/
Xchar *domain;		/* output domain 	*/
Xchar *user;		/* output user 		*/
X{
X	int parts;
X	char *partv[MAXPATH];				/* to crack address */
X
X/*
X**  If this is route address form @hosta, at hostb:user at hostd, break for
X**  LOCAL since only sendmail would want to eat it.
X*/
X	if (*address == '@')
X		goto local;
X/*
X**  Try splitting at @.  If it work, this is user at domain, form DOMAIN.
X**  Prefer the righthand @ in a at b@c.
X*/
X	if ((parts = ssplit(address, '@', partv)) >= 2) {
X		(void) strcpy(domain, partv[parts-1]);
X		(void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
X		user[partv[parts-1]-partv[0]-1] = '\0';
X		return (DOMAIN);
X	} 
X/*
X**  Try splitting at !. If it works, see if the piece before the ! has
X**  a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
X*/
X	if (ssplit(address, '!', partv) > 1) {
X		(void) strcpy(user, partv[1]);
X		(void) strncpy(domain, partv[0], partv[1]-partv[0]-1);
X		domain[partv[1]-partv[0]-1] = '\0';
X
X		if((parts = ssplit(domain, '.', partv)) < 2) {
X			return(UUCP);
X		}
X
X		if(partv[parts-1][0] == '\0') {
X			partv[parts-1][-1] = '\0'; /* strip trailing . */
X		}
X		return (DOMAIN);
X	}
X/* 
X**  Done trying.  This must be just a user name, form LOCAL.
X*/
Xlocal:
X	(void) strcpy(user, address);
X	(void) strcpy(domain, "");
X	return(LOCAL);				/* user */
X}
X
Xbuild(domain, user, form, result)
Xchar *domain;
Xchar *user;
Xenum eform form;
Xchar *result;
X{
X	switch((int) form) {
X	case LOCAL:
X		(void) sprintf(result, "%s", user); 
X		break;
X	case UUCP:
X		(void) sprintf(result, "%s!%s", domain, user);
X		break;
X	case DOMAIN:
X		(void) sprintf(result, "%s@%s", user, domain);
X		break;
X	}
X}
X
X/*
X**  ssplit(): split a line into array pointers.
X**
X**  Each pointer wordv[i] points to the first character after the i'th 
X**  occurence of c in buf.  Note that each wordv[i] includes wordv[i+1].
X**
X*/
X
Xssplit(buf, c, ptr)
Xregister char *buf;		/* line to split up 		*/
Xchar c;				/* character to split on	*/
Xchar **ptr;			/* the resultant vector		*/
X{
X        int count = 0;
X        int wasword = 0;
X
X        for(; *buf; buf++) {
X		if (!wasword) {
X			count++;
X			*ptr++ = buf;
X		}
X		wasword = (c != *buf);
X        }
X	if (!wasword) {
X		count++;
X		*ptr++ = buf;
X	}
X        *ptr = NULL;
X        return(count);
X}
X
X/*
X** Determine whether an address is a local address
X*/
X
Xislocal(addr, domain, user)
Xchar *addr, *domain, *user;
X{
X		enum eform form, parse();
X
X		/*
X		** parse the address
X		*/
X
X		form = parse(addr, domain, user);
X
X		if((form == LOCAL)			/* user */
X		||(strcmpic(domain, hostdomain) == 0)	/* user at hostdomain */
X		||(strcmpic(domain, hostname)   == 0)) {/* user at hostname */
X			return(1);
X		}
X		return(0);
X}
X
X/*
X** spool - message spooling module
X**
X** (1) get dates for headers, etc.
X** (2) if the message is on the standard input (no '-f')
X**     (a) create a temp file for spooling the message.
X**     (b) collapse the From_ headers into a path.
X**     (c) if the mail originated locally, then
X**	     (i) establish default headers
X**	    (ii) scan the message headers for required header fields
X**	   (iii) add any required message headers that are absent
X**     (d) copy rest of the message to the spool file
X**     (e) close the spool file
X** (3) open the spool file for reading
X*/
X
Xvoid
Xspool(argc, argv)
Xint argc;
Xchar **argv;
X{
X	static char *tmpf = "/tmp/rmXXXXXX";	/* temp file name */
X	char *mktemp();
X	char buf[SMLBUF];
X	static char splbuf[SMLBUF];
X	char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
X	void rline(), scanheaders(), compheaders();
X
X	/*
X	** if the mail has already been spooled by
X	** a previous invocation of smail don't respool.
X	** check the file name to prevent things like
X	** rmail -f /etc/passwd badguy at dreadfuldomain
X	*/
X
X	if((spoolfile != NULL)
X	&& (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) {
X		error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile);
X	}
X
X	/*
X	** set dates in local, arpa, and gmt forms
X	*/
X	setdates();
X
X	/*
X	** If necessary, copy stdin to a temp file.
X	*/
X
X	if(spoolfile == NULL) {
X		spoolfile = strcpy(splbuf, tmpf);
X		(void) mktemp(spoolfile);
X
X		if((spoolfp = fopen(spoolfile, "w")) == NULL) {
X			error(EX_CANTCREAT, "can't create %s.\n", spoolfile);
X		}
X
X		spoolmaster = 1;
X
X		/*
X		** rline reads the standard input,
X		** collapsing the From_ and >From_
X		** lines into a single uucp path.
X		** first non-from_ line is in buf[];
X		*/
X
X		rline(from, buf);
X
X		/*
X		** if the mail originated here, we parse the header
X		** and add any required headers that are missing.
X		*/
X
X		if(islocal(from, domain, user)) {
X			/*
X			** initialize default headers
X			*/
X			def_headers(argc, argv, from);
X
X			/*
X			** buf has first, non-from_  line
X			*/
X			scanheaders(buf);
X			/*
X			** buf has first, non-header line,
X			*/
X
X			compheaders();
X
X			if(buf[0] != '\n') {
X				(void) fputs("\n", spoolfp);
X			}
X		}
X
X		/*
X		** now, copy the rest of the letter into the spool file
X		** terminate on either EOF or '^.$'
X		*/
X
X		while(ieof != NULL) {
X			(void) fputs(buf, spoolfp);
X			if((fgets(buf, SMLBUF, stdin) == NULL)
X			|| (buf[0] == '.' && buf[1] == '\n')) {
X				ieof = NULL;
X			}
X		}
X
X		/*
X		** close the spool file, and the standard input.
X		*/
X
X		(void) fclose(spoolfp);
X		(void) fclose(stdin);	/* you don't see this too often! */
X	}
X
X	if((spoolfp = fopen(spoolfile, "r")) == NULL) {
X		error(EX_TEMPFAIL, "can't open %s.\n", spoolfile);
X	}
X}
X
X/*
X**
X**  rline(): collapse From_ and >From_ lines.
X**
X**  Same idea as the old rmail, but also turns user at domain to domain!user. 
X**
X*/
X
Xvoid
Xrline(from, retbuf)
Xchar *from;
Xchar *retbuf;
X{
X	int parts;			/* for cracking From_ lines ... */
X	char *partv[16];		/* ... apart using ssplit() 	*/
X	char user[SMLBUF];		/* for rewriting user at host	*/
X	char domain[SMLBUF];		/* "   "         "          	*/
X	char addr[SMLBUF];		/* "   "         "          	*/
X	enum eform form, parse();	/* "   "         "          	*/
X	extern build();			/* "   "         "          	*/
X	struct passwd *pwent, *getpwuid();/* to get default user	*/
X	char *c;
X	int nhops, i;
X	char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b, *p;
X
X	if(spoolmaster == 0) return;
X
X	buf[0] = from[0] = addr[0] = '\0';
X/*
X**  Read each line until we hit EOF or a line not beginning with "From "
X**  or ">From " (called From_ lines), accumulating the new path in from
X**  and stuffing the actual sending user (the user name on the last From_ 
X**  line) in addr.
X*/
X	for(;;) {
X		(void) strcpy(retbuf, buf);
X		if(ieof == NULL) {
X			break;
X		}
X		if((fgets(buf, sizeof(buf), stdin) == NULL)
X		|| (buf[0] == '.' && buf[1] == '\n')) {
X			ieof = NULL;
X			break;
X		}
X		if (strncmp("From ", buf, 5) 
X		    && strncmp(">From ", buf, 6)) {
X			break;
X		}
X/*
X**  Crack the line apart using ssplit.
X*/
X		if(c = index(buf, '\n')) {
X			*c = '\0';
X		}
X		parts = ssplit(buf, ' ', partv);
X/*
X**  Tack host! onto the from argument if "remote from host" is present.
X*/
X
X		if (parts > 3 
X		    && !strncmp("remote from ", partv[parts-3], 12))
X		{
X			(void) strcat(from, partv[parts-1]);
X			(void) strcat(from, "!");
X		} 
X/*
X**  Stuff user name into addr, overwriting the user name from previous 
X**  From_ lines, since only the last one counts.  Then rewrite user at host 
X**  into host!user, since @'s don't belong in the From_ argument.
X*/
X		(void) strncpy(addr, partv[1], partv[2]-partv[1]-1); 
X		addr[partv[2]-partv[1]-1] = '\0';	/* ugh */
X
X		(void) parse(addr, domain, user);
X		if(*domain == '\0') {
X			form = LOCAL;
X		} else {
X			form = UUCP;
X		}
X
X		build(domain, user, form, addr);
X	}
X/*
X**  Now tack the user name onto the from argument.
X*/
X	(void) strcat(from, addr);
X/*
X**  If we still have no from argument, we have junk headers, but we try
X**  to get the user's name using /etc/passwd.
X*/
X	if (from[0] == '\0') {
X		if ((pwent = getpwuid(getuid())) == NULL) {
X			(void) strcpy(from, "nowhere");	/* bad news */
X		} else {
X			(void) strcpy(from, pwent->pw_name);
X		}
X	}
X
X	/* split the from line on '!'s */
X	nhops = ssplit(from, '!', hop);
X
X	for(i = 0; i < (nhops - 1); i++) {
X		b = hop[i];
X		if(*b == '\0') {
X			continue;
X		}
X		e = hop[i+1];
X		e-- ;
X		*e = '\0';	/* null terminate each path segment */
X		e++;
X
X#ifdef HIDDENHOSTS
X/*
X**  Strip hidden hosts:  anything.hostname.MYDOM -> hostname.MYDOM
X*/
X		for(p = b;(p = index(p, '.')) != NULL; p++) {
X			if(strcmpic(hostdomain, p+1) == 0) {
X				(void) strcpy(b, hostdomain);
X				break;
X			}
X		}
X#endif
X
X/*
X**  Strip useless MYDOM: hostname.MYDOM -> hostname
X*/
X		if(strcmpic(hop[i], hostdomain) == 0) {
X			(void) strcpy(hop[i], hostname);
X		}
X	}
X
X/*
X**  Now strip out any redundant information in the From_ line
X**  a!b!c!c!d	=> a!b!c!d
X*/
X
X	for(i = 0; i < (nhops - 2); i++) {
X		b = hop[i];
X		e = hop[i+1];
X		if(strcmpic(b, e) == 0) {
X			*b = '\0';
X		}
X	}
X/*
X**  Reconstruct the From_ line
X*/
X	tmp[0] = '\0';			/* empty the tmp buffer */
X
X	for(i = 0; i < (nhops - 1); i++) {
X		if((hop[i][0] == '\0')	/* deleted this hop */
X		 ||((tmp[0] == '\0')	/* first hop == hostname */
X		  &&(strcmpic(hop[i], hostname) == 0))) {
X			continue;
X		}
X		(void) strcat(tmp, hop[i]);
X		(void) strcat(tmp, "!");
X	}
X	(void) strcat(tmp, hop[i]);
X	(void) strcpy(from, tmp);
X	(void) strcpy(retbuf, buf);
X	(void) fprintf(spoolfp, "%s\n", from);
X}
X
Xvoid
Xscanheaders(buf)
Xchar *buf;
X{
X	int inheader = 0;
X
X	while(ieof != NULL) {
X		if(buf[0] == '\n') {
X			break; /* end of headers */
X		}
X
X		/*
X		** header lines which begin with whitespace
X		** are continuation lines
X		*/
X		if((inheader == 0)
X		|| ((buf[0] != ' ' && buf[0] != '\t'))) {
X			/* not a continuation line
X			** check for header
X			*/
X			if(isheader(buf) == 0) {
X				/*
X				** not a header
X				*/
X				break;
X			}
X			inheader = 1;
X			haveheaders(buf);
X		}
X		(void) fputs(buf, spoolfp);
X		if((fgets(buf, SMLBUF, stdin) == NULL)
X		|| (buf[0] == '.' && buf[1] == '\n')) {
X			ieof = NULL;
X		}
X	}
X
X	if(isheader(buf)) {
X		buf[0] = '\0';
X	}
X}
X
X/*
X** complete headers - add any required headers that are not in the message
X*/
Xvoid
Xcompheaders()
X{
X	struct reqheaders *i;
X
X	/*
X	** look at the table of required headers and
X	** add those that are missing to the spooled message.
X	*/
X	for(i = reqtab; i->name != NULL; i++) {
X		if(i->have != 'Y') {
X			(void) fprintf(spoolfp, "%s\n", i->field);
X		}
X	}
X}
X
X/*
X** look at a string and determine
X** whether or not it is a valid header.
X*/
Xisheader(s)
Xchar *s;
X{
X	char *p;
X
X	/*
X	** header field names must terminate with a colon
X	** and may not be null.
X	*/
X	if(((p = index(s, ':')) == NULL) || (s == p)) {
X		return(0);
X
X	}
X	/*
X	** header field names must consist entirely of
X	** printable ascii characters.
X	*/
X	while(s != p) {
X		if((*s < '!') || (*s > '~')) {
X			return(0);
X		}
X		s++;
X	}
X	/*
X	** we hit the ':', so the field may be a header
X	*/
X	return(1);
X}
X
X/*
X** compare the header field to those in the required header table.
X** if it matches, then mark the required header as being present
X** in the message.
X*/
Xhaveheaders(s)
Xchar *s;
X{
X	struct reqheaders *i;
X
X	for(i = reqtab; i->name != NULL; i++) {
X		if(strncmpic(i->name, s, strlen(i->name)) == 0) {
X			i->have = 'Y';
X			break;
X		}
X	}
X}
X
X/*
X** create default headers for the message.
X*/
Xdef_headers(argc, argv, from)
Xint argc;
Xchar **argv;
Xchar *from;
X{
X	def_to(argc, argv);	/* default To:		*/
X	def_date();		/* default Date:	*/
X	def_from(from);		/* default From: 	*/
X	def_mid();		/* default Message-Id:	*/
X}
X
X/*
X** default Date: in arpa format
X*/
Xdef_date()
X{
X	(void) strcpy(dateline, "Date: ");
X	(void) strcat(dateline, arpanows);
X}
X
X/*
X** default Message-Id
X**  Message-Id: <yymmddhhmm.AAppppp at hostdomain>
X**
X**	yy	 year
X**	mm	 month
X**	dd	 day
X**	hh	 hour
X**	mm	 minute
X**	ppppp	process-id
X**
X** date and time are set by GMT
X*/
Xdef_mid()
X{
X	(void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>",
X		gmt->tm_year,
X		gmt->tm_mon+1,
X		gmt->tm_mday,
X		gmt->tm_hour,
X		gmt->tm_min,
X		getpid(),
X		hostdomain);
X}
X
X/*
X** default From:
X**  From: user at hostdomain
X*/
Xdef_from(from)
Xchar *from;
X{
X	(void) sprintf(fromline, "From: %s@%s", from, hostdomain);
X}
X
X/*
X** default To:
X**  To: recip1, recip2, ...
X**
X** lines longer than 50 chars are continued on another line.
X*/
Xdef_to(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int i, n;
X	char *bol;
X
X	bol = toline;
X	(void) strcpy(bol, "To:");
X	for(n = i = 0; i < argc; i++) {
X		n = strlen(bol);
X		if(n > 50) {
X			(void) strcat(bol, "\n\t");
X			bol = bol + strlen(bol);
X			*bol = '\0';
X			n = 8;
X		}
X		if(i == 0) {
X			(void) strcat(bol, " ");
X		} else {
X			(void) strcat(bol, ", ");
X		}
X		(void) strcat(bol, argv[i]);
X	}
X}
@//E*O*F src/headers.c//
if test 13909 -ne "`wc -c <'src/headers.c'`"; then
    echo shar: error transmitting "'src/headers.c'" '(should have been 13909 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/main.c'" '(4213 characters)'
if test -f 'src/main.c' ; then 
  echo shar: will not over-write existing file "'src/main.c'"
else
sed 's/^X//' >src/main.c <<'@//E*O*F src/main.c//'
X/*
X**
X**  rmail/smail - UUCP mailer with automatic routing.
X**
X**  Christopher Seiwald		/+\
X**  chris at cbosgd.att.com	+\
X**  January, 1985		\+/
X**
X*/
X
X#ifndef lint
Xstatic char 	*sccsid="@(#)main.c	2.2 (smail) 1/26/87";
X#endif
X
X/*
X**
X**  usage:  	rmail [options] address...
X**		smail [options] address...
X**  options:
X**		-d 		debug - verbose and don't invoke mailers.
X**		-v		verbose - just verbose.
X**		-h hostname	set hostname 
X**		-H hostdomain	set hostdomain (default hostname.MYDOM)
X**		-p pathfile	path database filename
X**		-r		force routing of host!address
X**		-R		reroute even explicit path!user
X**		-l		user at domain goes to local mailer
X**		-L		all mail goes local
X**		-q number	mail queueing cost threshold
X**		-m number	limit on number of uux_noqueue jobs
X**		-u string	string of flags for uux
X**		-a aliasfile	aliases filename (not used with SENDMAIL)
X*/
X
X#include	<stdio.h>
X#include	<ctype.h>
X#include	"defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xint exitstat = 0;		/* exit status, set by resolve, deliver	*/
X
Xenum edebug debug     = NO;	/* set by -d or -v option		*/
Xenum ehandle handle   = HANDLE;	/* which mail we can handle, see defs.h	*/
Xenum erouting routing = ROUTING;/* to route or not to route, see defs.h */
X
Xchar hostname[SMLBUF]   = "";	/* set by -h, defaults in defs.h 	*/
Xchar hostdomain[SMLBUF] = "";	/* set by -H, defaults in defs.h 	*/
X
Xchar *pathfile  = PATHS;	/* or set by -p 			*/
Xchar *uuxargs   = NULL;		/* or set by -u				*/
Xchar *aliasfile = ALIAS;	/* or set by -a				*/
Xint  queuecost  = QUEUECOST;	/* or set by -q				*/
Xint  maxnoqueue = MAXNOQUEUE;	/* or set by -m                         */
X
Xchar *spoolfile = NULL;		/* name of the file containing letter   */
XFILE *spoolfp;			/* file pointer to spoolfile		*/
Xint  spoolmaster = 0;		/* indicates 'control' of spoolfile     */
Xvoid spool();
X
X
X/*
X**
X**  rmail/smail: mail stdin letter to argv addresses.
X**
X**  After processing command line options and finding our host and domain 
X**  names, we map addresses into <host,user,form,cost> sets.  Then we deliver.
X**
X*/
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X{
X	char *hostv[MAXARGS];		/* UUCP neighbor 		*/
X	char *userv[MAXARGS];		/* address given to host 	*/
X	int  costv[MAXARGS];		/* cost of resolved route	*/
X	enum eform formv[MAXARGS];	/* invalid, local, or uucp 	*/
X	char *p;
X	int c;
X	int nargc;
X	char **nargv, **alias();
X
X	char *optstr = "dvrRlLH:h:p:u:q:a:m:f:";
X	extern char *optarg;
X	extern int optind;
X
X/*
X**  see if we aren't invoked as rmail
X*/
X	if((p = rindex(argv[0], '/')) == NULL) {
X		p = argv[0];
X	} else {
X		p++;
X	}
X
X	if(*p != 'r' ) {
X		handle = ALL;
X	}
X
X/*
X**  Process command line arguments
X*/
X	while ((c = getopt(argc, argv, optstr)) != EOF) {
X		switch ( c ) {
X		case 'd': debug      = YES; 		break;
X		case 'v': debug      = VERBOSE; 	break; 
X		case 'r': routing    = ALWAYS;		break;
X		case 'R': routing    = REROUTE;		break;
X		case 'l': handle     = JUSTUUCP;	break;
X		case 'L': handle     = NONE;		break;
X		case 'f': spoolfile  = optarg;		break;
X		case 'p': pathfile   = optarg; 		break;
X		case 'u': uuxargs    = optarg; 		break;
X		case 'a': aliasfile  = optarg; 		break;
X		case 'H': (void) strcpy(hostdomain, optarg);	break;
X		case 'h': (void) strcpy(hostname, optarg); 	break;
X		case 'm': if(isdigit(*optarg)) {
X				  maxnoqueue = atoi(optarg);
X			  }
X			  break;
X		case 'q': if(isdigit(*optarg)) {
X				  queuecost = atoi(optarg);
X			  }
X			  break;
X		default:
X			error( EX_USAGE, "valid flags are %s\n", optstr);
X		}
X	}
X	if ( argc <= optind ) {
X		error( EX_USAGE, "usage: %s [flags] address...\n", argv[0] );
X	}
X
X/*
X**  Get our default hostname and hostdomain.
X*/
X	getmynames();
X
X/*
X**  Spool the letter in a temporary file.
X*/
X	nargc = argc - optind;
X	spool(nargc, &argv[optind]);
X
X/*
X** If we have sendmail, aliasing was done there, so alias() is a NOP.
X** If we don't have sendmail, do our own aliasing.
X*/
X	nargv = alias(&nargc, &argv[optind]);
X
X/*
X**  Map argv addresses to <host, user, form, cost>.
X*/
X	map(nargc, nargv, hostv, userv, formv, costv);
X/*
X**  Deliver.
X*/
X	deliver(nargc, hostv, userv, formv, costv);
X/*
X**  Exitstat was set if any resolve or deliver failed, otherwise 0.
X*/
X	return( exitstat );
X}
@//E*O*F src/main.c//
if test 4213 -ne "`wc -c <'src/main.c'`"; then
    echo shar: error transmitting "'src/main.c'" '(should have been 4213 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/make.cf.sh'" '(3038 characters)'
if test -f 'src/make.cf.sh' ; then 
  echo shar: will not over-write existing file "'src/make.cf.sh'"
else
sed 's/^X//' >src/make.cf.sh <<'@//E*O*F src/make.cf.sh//'
X#! /bin/sh
X#
X# @(#)make.cf.sh	2.1 (smail) 12/14/86
X#
Xcat <<!EOM!
XThis script will prompt you for the automatically configurable parameters
Xin the stock version of the sendmail configuration file.  Naturally, any
Xlocal extensions will have to be added manually.
X
XClyde is a VAX running AT&T System V Release 2.0, with a port of sendmail.
XClyde is a gateway for the domain .att.com.
X
XBelow is a trace of the session that
Xconfigured the sendmail.cf on clyde.ATT.COM:
X===
X
X!EOM!
X
Xecho "press return to continue"; read foo
X
Xcat <<!EOM!
XEnter Date (MM-DD-YY):
X06-24-86
XEnter This Host's Name:
Xclyde
XEnter This Host's Official Domain:
XATT.COM
XEnter Any Equivalent Domain Classes:
XATT
XEnter Any Domains For Which This Host Is An Authority:
XATT.UUCP
XDoes This Host Have SMTP Connections (y/n)?
Xno
XEnter Full Path to Executable That Will Provide Local Mail Delivery:
X/bin/lmail
XIs /bin/lmail A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?
Xno
XWill This Host Act As A Gateway Between Domains (y/n)?
Xyes
XAre subdomains beneath this hosts' domain to be hidden (y/n)?
Xyes
X===
X!EOM!
X# get date of configuration
XCF_DATE=`/bin/sh ./smail.prompt string "Enter Date (MM-DD-YY):"`
X
X# get host name
XCF_HOST=`/bin/sh ./smail.prompt string "Enter This Host's Name:"`
X
X# get host domain
XCF_DOMAIN=`/bin/sh ./smail.prompt string "Enter This Host's Official Domain:"`
X
X# get domain classes
XCF_DCLASS=`/bin/sh ./smail.prompt string "Enter Any Equivalent Domain Classes:"`
X
X# get domain authority
XCF_AUTHORITY=`/bin/sh ./smail.prompt string "Enter Any Domains For Which This Host Is An Authority:"`
X
XCF_SMTP=`/bin/sh ./smail.prompt yesno "Does This Host Have SMTP Connections (y/n)?"`
Xif test "$CF_SMTP" = "yes"
Xthen
X
X#get list of local SMTP connections
X	CF_SMTP=`/bin/sh ./smail.prompt file "Enter Full Path to File that Contains List of SMTP Connections:"`
X
X	CF_SMTP="FE$CF_SMTP %s"
Xelse
X	CF_SMTP=""
Xfi
X
X# get path to local delivery agent
XCF_LOCALMAIL=`/bin/sh ./smail.prompt file "Enter Full Path to Executable That Will Provide Local Mail Delivery:"`
X
XCF_SYSTEM=`/bin/sh ./smail.prompt yesno "Is $CF_LOCALMAIL A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?"`
Xif test "$CF_SYSTEM" = "yes"
Xthen
X	CF_SVMAIL="#"
X	CF_BSMAIL=""
Xelse
X	CF_SVMAIL=""
X	CF_BSMAIL="#"
Xfi
X
XCF_GATEWAY=`/bin/sh ./smail.prompt yesno "Will This Host Act As A Gateway Between Domains(y/n)?"`
Xif test "$CF_GATEWAY" = "yes"
Xthen
X	CF_GATEWAY=""
Xelse
X	CF_GATEWAY="#"
Xfi
X
XCF_HIDDENHOSTS=`/bin/sh ./smail.prompt yesno "Are subdomains beneath this hosts' domain to be hidden (y/n)?"`
Xif test "$CF_HIDDENHOSTS" = "yes"
Xthen
X	CF_HIDDENHOSTS=""
Xelse
X	CF_HIDDENHOSTS="#"
Xfi
X
Xsed 	\
X	-e "s/CF_HOST/Dw$CF_HOST/" \
X	-e "s/CF_DOMAIN/DD$CF_DOMAIN/" \
X	-e "s/CF_AUTHORITY/DA$CF_AUTHORITY/" \
X	-e "s/CF_DCLASS/CDUUCP $CF_DCLASS/" \
X	-e "s;CF_SMTP;$CF_SMTP;" \
X	-e "s;CF_DATE;$CF_DATE;" \
X	-e "s;CF_LOCALMAIL;$CF_LOCALMAIL;" \
X	-e "s;CF_BSMAIL;$CF_BSMAIL;" \
X	-e "s;CF_SVMAIL;$CF_SVMAIL;" \
X	-e "s;CF_GATEWAY;$CF_GATEWAY;" \
X	-e "s;CF_HIDDENHOSTS;$CF_HIDDENHOSTS;" \
X	template.cf > sendmail.cf
@//E*O*F src/make.cf.sh//
if test 3038 -ne "`wc -c <'src/make.cf.sh'`"; then
    echo shar: error transmitting "'src/make.cf.sh'" '(should have been 3038 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/map.c'" '(1425 characters)'
if test -f 'src/map.c' ; then 
  echo shar: will not over-write existing file "'src/map.c'"
else
sed 's/^X//' >src/map.c <<'@//E*O*F src/map.c//'
X#ifndef lint
Xstatic char 	*sccsid="@(#)map.c	2.2 (smail) 1/26/87";
X#endif
X
X# include	<stdio.h>
X# include	<sys/types.h>
X# include	"defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int queuecost;
X
X/*
X**
X**  map(): map addresses into <host, user, form, cost> sets.
X**
X**  Calls resolve() for each address of argv.  The result is hostv and 
X**  userv arrays (pointing into buffers userz and hostz), and formv array.
X**
X*/
X
Xmap(argc, argv, hostv, userv, formv, costv)
Xint argc;				/* address count 		*/
Xchar **argv;				/* address vector 		*/
Xchar *hostv[];				/* remote host vector 		*/
Xchar *userv[];				/* user name vector 		*/
Xenum eform formv[];			/* address format vector 	*/
Xint costv[];				/* cost vector 			*/
X{
X	int i, cost;
X	enum eform resolve();
X	char *c;
X	static char userbuf[BIGBUF], *userz;
X	static char hostbuf[BIGBUF], *hostz;
X
X	userz = userbuf;
X	hostz = hostbuf;
X
X	for( i=0; i<argc; i++ ) {
X#ifdef DEFQUEUE
X		cost = queuecost+1;		/* default is queueing */
X#else
X		cost = queuecost-1;		/* default is no queueing */
X#endif
X		userv[i] = userz;		/* put results here */
X		hostv[i] = hostz;
X		if ( **argv == '(' ) {		/* strip () */
X			++*argv;
X			c = index( *argv, ')' );
X			if (c)
X				*c = '\0';
X		}
X						/* here it comes! */
X		formv[i] = resolve(*argv++, hostz, userz, &cost);
X		costv[i] = cost;
X		userz += strlen( userz ) + 1;	/* skip past \0 */
X		hostz += strlen( hostz ) + 1;
X	}
X}
@//E*O*F src/map.c//
if test 1425 -ne "`wc -c <'src/map.c'`"; then
    echo shar: error transmitting "'src/map.c'" '(should have been 1425 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/misc.c'" '(7381 characters)'
if test -f 'src/misc.c' ; then 
  echo shar: will not over-write existing file "'src/misc.c'"
else
sed 's/^X//' >src/misc.c <<'@//E*O*F src/misc.c//'
X
X/*
X**  Miscellaneous support functions for smail/rmail
X*/
X
X#ifndef lint
Xstatic char 	*sccsid="@(#)misc.c	2.3 (smail) 1/26/87";
X#endif
X
X# include	<stdio.h>
X# include	<sys/types.h>
X# include	<ctype.h>
X# include	"defs.h"
X#ifdef BSD
X# include	<sys/time.h>
X# include	<sys/timeb.h>
X# include	<strings.h>
X#else
X# include	<time.h>
X# include	<sys/utsname.h>
X# include	<string.h>
X#endif
X
Xextern int  exitstat;		/* set if a forked mailer fails */
Xextern enum edebug debug;	/* how verbose we are 		*/ 
Xextern enum ehandle handle;	/* what we handle		*/
Xextern char *uuxargs;		/* arguments given to uux       */
Xextern int  queuecost;		/* threshold for queueing mail  */
Xextern int  maxnoqueue;		/* max number of uucico's       */
Xextern enum erouting routing;	/* when to route addresses	*/
Xextern char hostdomain[];	/* */
Xextern char hostname[];		/* */
Xextern char *pathfile;		/* location of path database	*/
Xextern char *spoolfile;		/* file name of spooled message */
Xextern FILE *spoolfp;		/* file ptr  to spooled message */
Xextern int spoolmaster;		/* set if creator of spoolfile  */
X
Xstruct tm *gmt, *loc;		/* GMT and local time structure	*/
Xtime_t now;			/* current system time		*/
Xchar nows[50];			/* time in ctime format		*/
Xchar arpanows[50];		/* time in arpa format		*/
X
X# ifdef LOG
Xvoid
Xlog(command, from, size)
Xchar *command, *from;
Xlong size;
X{
X	FILE *fd;
X	char *logtime, tbuf[50];
X	int cmask;
X
X	logtime = strcpy(tbuf, nows);
X	logtime[16] = '\0';
X	logtime += 4;
X
X	cmask = umask(0);
X	fd = fopen(LOG, "a");
X	(void) umask(cmask);
X
X	if (fd != NULL) {
X		(void) fprintf(fd, "%s\t%ld\t%s\t%s\n",
X			logtime, size, from, command);
X		(void) fclose(fd);
X	}
X}
X# endif
X
X# ifdef RECORD
XFILE *
Xrecord(command, from, size)
Xchar *command, *from;
Xlong size;
X{
X	FILE *fd;
X	char *logtime, buf[SMLBUF];
X	int cmask;
X
X	logtime = strcpy(buf, nows);
X	logtime[16] = 0;
X	logtime += 4;
X
X	cmask = umask(0);
X	fd = fopen(RECORD, "a");
X	(void) umask(cmask);
X
X	if (fd != NULL) {
X		(void) fprintf(fd, "%s: %s, from %s, %ld bytes\n", 
X			logtime, command, from, size);
X	}
X	while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X		(void) fputs(buf, fd);
X	}
X	(void) fclose(fd);
X}
X# endif
X
X
Xsetdates()
X{
X	time_t time();
X	struct tm *gmtime();
X	char *ctime(), *arpadate();
X
X	(void) time(&now);
X	(void) strcpy(nows, ctime(&now));
X	gmt = gmtime(&now);
X	loc = localtime(&now);
X	(void) strcpy(arpanows, arpadate(nows));
X}
X
X/*
X**  Note: This routine was taken from sendmail
X**
X**  ARPADATE -- Create date in ARPANET format
X**
X**	Parameters:
X**		ud -- unix style date string.  if NULL, one is created.
X**
X**	Returns:
X**		pointer to an ARPANET date field
X**
X**	Side Effects:
X**		none
X**
X**	WARNING:
X**		date is stored in a local buffer -- subsequent
X**		calls will overwrite.
X**
X**	Bugs:
X**		Timezone is computed from local time, rather than
X**		from whereever (and whenever) the message was sent.
X**		To do better is very hard.
X**
X**		Some sites are now inserting the timezone into the
X**		local date.  This routine should figure out what
X**		the format is and work appropriately.
X*/
X
Xchar *
Xarpadate(ud)
X	register char *ud;
X{
X	register char *p;
X	register char *q;
X	static char b[40];
X	extern char *ctime();
X	register int i;
X	extern struct tm *localtime();
X#ifndef BSD
X	extern char *tzname[];
X	time_t t, time();
X#else
X	/* V7 and 4BSD */
X	struct timeb t;
X	extern struct timeb *ftime();
X	extern char *timezone();
X#endif
X
X	/*
X	**  Get current time.
X	**	This will be used if a null argument is passed and
X	**	to resolve the timezone.
X	*/
X
X#ifndef BSD
X	(void) time(&t);
X	if (ud == NULL)
X		ud = ctime(&t);
X#else
X	/* V7 or 4BSD */
X	ftime(&t);
X	if (ud == NULL)
X		ud = ctime(&t.time);
X#endif
X
X	/*
X	**  Crack the UNIX date line in a singularly unoriginal way.
X	*/
X
X	q = b;
X
X	p = &ud[8];		/* 16 */
X	if (*p == ' ')
X		p++;
X	else
X		*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[4];		/* Sep */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[22];		/* 1979 */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[11];		/* 01:03:52 */
X	for (i = 8; i > 0; i--)
X		*q++ = *p++;
X
X				/* -PST or -PDT */
X#ifndef BSD
X	p = tzname[localtime(&t)->tm_isdst];
X#else
X	p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
X#endif
X	if (p[3] != '\0')
X	{
X		/* hours from GMT */
X		p += 3;
X		*q++ = *p++;
X		if (p[1] == ':')
X			*q++ = '0';
X		else
X			*q++ = *p++;
X		*q++ = *p++;
X		p++;		/* skip ``:'' */
X		*q++ = *p++;
X		*q++ = *p++;
X	}
X	else
X	{
X		*q++ = ' ';
X		*q++ = *p++;
X		*q++ = *p++;
X		*q++ = *p++;
X	}
X
X	p = &ud[0];		/* Mon */
X	*q++ = ' ';
X	*q++ = '(';
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ')';
X
X	*q = '\0';
X	return (b);
X}
X
X/*
X *	The user name "postmaster" must be accepted regardless of what
X *	combination of upper and lower case is used.  This function is
X *	used to convert all case variants of "postmaster" to all lower
X *	case.  If the user name passed in is not "postmaster", it is
X *	returned unchanged.
X */
Xchar *
Xpostmaster(user)
Xchar *user;
X{
X	static char *pm = "postmaster";
X
X	if(strcmpic(user, pm) == 0) {
X		return(pm);
X	} else {
X		return(user);
X	}
X}
X
X/*
X**	strncmpic: string compare, ignore case, stop after 'n' chars
X*/
X
Xstrncmpic(s1, s2, n)
Xchar *s1, *s2;
Xint n;
X{
X	register char *u = s1;
X	register char *p = s2;
X
X	while((n > 0) && (*p != '\0')) {
X		/* chars match or only case different */
X		if(lower(*u) == lower(*p)) {
X			p++;	/* examine next char */
X			u++;
X		} else {
X			break;	/* no match - stop comparison */
X		}
X		n--;
X	}
X	if(n > 0) {
X		return(lower(*u) - lower(*p)); /* return "difference" */
X	} else {
X		return(0);
X	}
X}
X
X/*
X**	strcmpic: string compare, ignore case
X*/
X
Xstrcmpic(s1, s2)
Xchar *s1, *s2;
X{
X	register char *u = s1;
X	register char *p = s2;
X
X	while(*p != '\0') {
X		/* chars match or only case different */
X		if(lower(*u) == lower(*p)) {
X			p++;	/* examine next char */
X			u++;
X		} else {
X			break;	/* no match - stop comparison */
X		}
X	}
X
X	return(lower(*u) - lower(*p)); /* return "difference" */
X}
X
X/*
X * Return 1 iff the string is "UUCP" (ignore case).
X */
Xisuucp(str)
Xchar *str;
X{
X	if(strcmpic(str, "UUCP") == 0) {
X		return(1);
X	} else {
X		return(0);
X	}
X}
X
X/*
X** sform(form) returns a pointer to a string that tells what 'form' means
X*/
X
Xchar *
Xsform(form)
Xenum eform form;
X{
X	if(form == ERROR)  return("ERROR");
X	if(form == LOCAL)  return("LOCAL");
X	if(form == DOMAIN) return("DOMAIN");
X	if(form == UUCP)   return("UUCP");
X	if(form == ROUTE)  return("ROUTE");
X	return("UNKNOWN");
X}
X
X/*
X**
X**  getmynames(): what is my host name and host domain?
X**
X**  Hostname set by -h, failing that by #define HOSTNAME, failing
X**  that by gethostname() or uname().
X**  
X**  Hostdomain set by -h, failing that by #define HOSTDOMAIN,
X**  failing that as hostname.MYDOM, or as just hostname.
X**
X**  See defs.h for the inside story.
X**
X*/
X
Xgetmynames()
X{
X#ifdef HOSTNAME
X	if (!*hostname)
X		(void) strcpy(hostname, HOSTNAME);
X#endif
X#ifdef GETHOSTNAME
X	if (!*hostname)
X		gethostname(hostname, SMLBUF - 1);
X#endif
X#ifdef UNAME
X	if (!*hostname) {
X		struct utsname site;
X
X		if (uname(&site) < 0)
X			error(EX_SOFTWARE, "uname() call failed", 0);
X		(void) strcpy(hostname, site.nodename);
X	}
X#endif
X	if (!*hostname)
X		error(EX_SOFTWARE, "can't determine hostname.\n", 0);
X#ifdef HOSTDOMAIN
X	if (!*hostdomain)
X		(void) strcpy(hostdomain, HOSTDOMAIN);
X#endif
X#ifdef MYDOM
X	if (!*hostdomain)
X		(void) strcat(strcpy(hostdomain, hostname), MYDOM);
X#endif
X	if (!*hostdomain)
X		(void) strcpy(hostdomain, hostname);
X
X}
@//E*O*F src/misc.c//
if test 7381 -ne "`wc -c <'src/misc.c'`"; then
    echo shar: error transmitting "'src/misc.c'" '(should have been 7381 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/resolve.c'" '(7236 characters)'
if test -f 'src/resolve.c' ; then 
  echo shar: will not over-write existing file "'src/resolve.c'"
else
sed 's/^X//' >src/resolve.c <<'@//E*O*F src/resolve.c//'
X/*
X**
X**  Resolve.c
X**
X**  Routes then resolves addresses into UUCP or LOCAL.
X**
X*/
X#ifndef lint
Xstatic char 	*sccsid="@(#)resolve.c	2.2 (smail) 1/26/87";
X#endif
X
X#include	<ctype.h>
X#include	<stdio.h>
X#include	"defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int exitstat;		/* set if address doesn't resolve 	*/
Xextern enum ehandle handle;	/* what mail we can handle		*/
Xextern enum edebug debug;	/* verbose and debug modes		*/
Xextern enum erouting routing;	/* when to route addresses		*/
Xextern char hostdomain[];	/* */
Xextern char hostname[];		/* */
Xextern char *pathfile;		/* location of path database		*/
X
Xchar *sform();
X
X/*
X**
X**  rsvp(): how to resolve addresses.
X**
X**  After parsing an address into <form>, the resolved form will be
X**  rsvp( form ).  If == ROUTE, we route the parsed address and parse again.
X**
X*/
X
X# define rsvp(a) table[(int)a][(int)handle]
X
Xenum eform table[5][3] = {
X/*	all		justuucp	none */
X{	ERROR, 		ERROR, 		ERROR }, 	/* error */
X{	LOCAL, 		LOCAL,	 	LOCAL }, 	/* local */
X{	ROUTE, 		LOCAL, 		LOCAL }, 	/* domain */
X{	UUCP, 		UUCP, 		LOCAL }, 	/* uucp */
X{	ERROR, 		ERROR, 		ERROR }};	/* route */
X
X/*
X**
X**  resolve(): resolve addresses to <host, user, form>.
X**
X**  This is a gnarly piece of code, but it does it all.  Each section 
X**  is documented.
X**
X*/
X
Xenum eform
Xresolve( address, domain, user , cost)
Xchar *address;				/* the input address 	*/
Xchar *domain;				/* the returned domain 	*/
Xchar *user;				/* the returned user 	*/
Xint *cost;				/* the returned cost 	*/
X{
X	enum eform form;		/* the returned form	*/ 
X	enum eform parse();		/* to crack addresses	*/
X	int parts;			/* to ssplit addresses	*/
X	char *partv[MAXPATH];		/* "  "      "		*/
X	char temp[SMLBUF];		/* "  "      "		*/
X	int i;
X		
X
X/*
X**  If we set REROUTE and are prepared to deliver UUCP mail, we split the 
X**  address apart at !'s and try to resolve successively larger righthand 
X**  substrings until we succeed.  Otherwise, we just resolve the whole thing 
X**  once.
X*/
X	if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
X		parts = ssplit( address, '!', partv );
X	} else {
X		parts = 1;
X		partv[0] = address;
X	}
X/*
X**  This for(i) loop selects successively larger
X**  righthand substrings of the address.
X*/
X	for( i = parts - 1; i >= 0; i-- ) {
X/*
X**  Parse the address.
X*/
X		(void) strcpy( temp, partv[i] );
X		form = parse( temp, domain, user );
X
XDEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
X	temp,user,domain,sform(form));
X
X/*
X**  If we are looking at a substring (that's not the entire string)
X**  which parses to a LOCAL address, we skip to the next larger substring.
X*/
X		if((i != 0) && (form == LOCAL))
X			continue;
X/*
X**  Routing, when required, is the next step.
X**  We route the address if we have a ROUTE form
X**  or if we have a UUCP form and we are told to
X**  route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
X*/
X		if((rsvp( form ) == ROUTE)
X		 ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
X
X			int look_smart = 0;
X
X			if((routing == REROUTE) && (i == 0)) {
X				look_smart = 1; /* last chance */
X			}
X
X			/* route() puts the new route in 'temp' */
X			if(route(domain,user,look_smart,temp,cost) != EX_OK) {
X				continue;	/* If routing fails, try
X						/* next larger substring.
X						/* */
X			}
X/*
X**  After routing, reparse the new route into domain and user. 
X*/
X			form = parse( temp, domain, user );
X
XDEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
X	temp,user,domain,sform(form));
X
X		}
X		break;	/* route is resolved */
X	}
X/*
X**  For LOCAL mail in non-local format, we rewrite the full address into 
X**  <user> and leave <domain> blank.
X*/
X	if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
X		build( domain, user, form, temp );
X		(void) strcpy( user, temp );
X		(void) strcpy( domain, "" );
X		form = LOCAL;
X	}
X/*
X**  If we were supposed to route an address but failed (form == ERROR), 
X**  or after routing we are left with an address that still needs to
X**  be routed (rsvp( form ) == ROUTE), complain.
X*/
X	if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
X		exitstat = EX_NOHOST;
X		ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
X			address, user, domain, sform(form));
X		form = ERROR;
X	} else {
X		ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
X			address, user, domain, sform(form));
X	}
X	return ( form );
X}
X
X/*
X**
X**  route(): route domain, plug in user.
X**
X**  Less complicated than it looks.  Each section is documented.
X**
X*/
X
Xroute(domain, user, look_smart, result, cost)
Xchar *domain;			/* domain or host name 	*/
Xchar *user;			/* user name 		*/
Xint look_smart;			/* do we try to route through a smarter host? */
Xchar *result;			/* output route 	*/
Xint *cost;			/* cost of output route */
X{
X	int	uucpdom = 0;
X	int	domains, step;			/* to split domain	*/
X	char	*domainv[MAXDOMS];		/* "  "     "		*/
X	char	temp[SMLBUF], path[SMLBUF];
X
X/*
X**  Fully qualify the domain, and then strip the last (top level domain) 
X**  component off, so that we look it up separately.
X*/
X	temp[0] = '.';
X	(void) strcpy(temp+1, domain );
X
X	domains = ssplit( temp+1, '.', domainv );
X
X/*
X** check target domain for the local host name and host domain.
X** if it matches, then the path skip the lookup in the database.
X** this prevents mail loops for cases where SMARTHOST is defined
X** in the routing table, but the local host is not.  It also is
X** a little faster when the local host is the target domain.
X*/
X	if((strcmpic(domain, hostname) == 0)
X	|| (strcmpic(domain, hostdomain) == 0)) {
X		step = 0;
X		*cost = 0;
X		(void) strcpy(path, "%s");
XDEBUG("route: '%s' is local\n", domain);
X		goto route_complete;
X	}
X
X	/* If the domain ends in .UUCP, trim that off. */
X	if((domains > 0) && isuucp(domainv[domains-1])) {
X		domains--;
X		domainv[domains][-1] = '\0';
X		uucpdom = 1;
X	}
X/*
X**  Try to get the path for successive components of the domain.  
X**  Example for osgd.cb.att.uucp:
X**	osgd.cb.att
X**	cb.att
X**	att
X**	uucp ( remember stripping top level? )
X**	SMARTHOST
X**  Returns with error if we find no path.
X*/
X	for(step = 0; (step < domains); step++) {
X		if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
X		|| (getpath(domainv[step]  , path, cost) == EX_OK))/* no dot */
X			break;
X	}
X
X	if(step == domains) {
X	/*
X	** we've looked at each component of the domain without success
X	*/
X		/*
X		** If domain is a UUCP address, look for a UUCP gateway.
X		*/
X		if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
X			/*
X			** The domain not is a UUCP address, or we can't
X			** find a UUCP gateway.  If this is our last chance,
X			** look for a smarter host to deliver the mail.
X			*/
X			if((look_smart == 0)
X			|| (getpath(SMARTHOST, path, cost) != EX_OK)) {
X				/*
X				** All our efforts have been in vain.
X				** Tell them the bad news.
X				*/
X				DEBUG("route '%s' failed\n", domain);
X				return( EX_NOHOST );
X			}
X		}
X	}
X
Xroute_complete:
X
XDEBUG("route:  '%s' (%s) = '%s' (%d)\n", domain, domainv[step], path, *cost);
X
X/*
X**  If we matched on the entire domain name, this address is fully resolved, 
X**  and we plug <user> into it.  If we matched on only part of the domain 
X**  name, we plug <domain>!<user> in.  
X*/
X	build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
X	(void) sprintf(result, path, temp);
X	return( EX_OK );
X}
@//E*O*F src/resolve.c//
if test 7236 -ne "`wc -c <'src/resolve.c'`"; then
    echo shar: error transmitting "'src/resolve.c'" '(should have been 7236 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/smail.prompt'" '(762 characters)'
if test -f 'src/smail.prompt' ; then 
  echo shar: will not over-write existing file "'src/smail.prompt'"
else
sed 's/^X//' >src/smail.prompt <<'@//E*O*F src/smail.prompt//'
X#
X# @(#)smail.prompt	2.1 (smail) 12/14/86
X#
X
Xloop=true
Xwhile test $loop = true
Xdo 
X	case "$1" in
X	string)
X		echo "$2" 1>&2
X		read ans
X		if test ! -z "$ans"
X		then
X			echo $ans
X			loop=false;
X		fi
X	;;
X	file)
X		echo "$2" 1>&2
X		read ans
X		case "$ans" in
X		/*)
X			if test -f "$ans"
X			then
X				echo $ans
X				loop=false;
X			else
X				echo "file '$ans' not found" 1>&2
X			fi
X		;;
X		*)
X			echo "must give FULL PATH to file" 1>&2
X		;;
X		esac
X	;;
X	yesno)
X		echo "$2" 1>&2
X		read ans
X		case "$ans" in
X		y|Y|yes|Yes|YES)
X			echo "yes"
X			loop=false
X		;;
X		n|N|no|No|NO)
X			echo "no"
X			loop=false
X		;;
X		*)
X			echo "Please enter yes or no" 1>&2
X		;;
X		esac
X	;;
X	*)
X
X		echo "usage: $0 string|yesno prompt_message" 1>&2
X		echo BOGUS_PROMPT_STRING
X		loop=false
X	;;
X	esac
Xdone
@//E*O*F src/smail.prompt//
if test 762 -ne "`wc -c <'src/smail.prompt'`"; then
    echo shar: error transmitting "'src/smail.prompt'" '(should have been 762 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/svbinmail.c'" '(1749 characters)'
if test -f 'src/svbinmail.c' ; then 
  echo shar: will not over-write existing file "'src/svbinmail.c'"
else
sed 's/^X//' >src/svbinmail.c <<'@//E*O*F src/svbinmail.c//'
X#ifndef lint
Xstatic char	*sccsid = "@(#)svbinmail.c	2.2 (smail) 1/26/87";
X#endif
X/* */
X/* This program will be used in place of /bin/mail on SVR2 sites.
X/* It looks at the arguments and decides whether to call
X/* SENDER for sending mail, or READER for reading mail.
X/*
X/* before installing as /bin/mail, move the stock /bin/mail to /bin/lmail
X/*
X/*  */
X
X#include <stdio.h>
X#include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#ifdef SENDMAIL
X#define SENDER	SENDMAIL
X#else
X#define	SENDER	"/bin/rmail"
X#endif
X
X#define	READER	"/bin/lmail"
X
X#define TRUE 1
X#define FALSE 0
X
Xchar prog[128];
X
Xvoid	perror(), exit(), usage();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X
X	int i, j, c;
X	int reading, sending;
X
X	reading = sending = FALSE;
X
X	(void) strcpy(prog, argv[0]);
X
X	if(argc == 1) {
X		reading = TRUE;
X	} else {
X		while((c = getopt(argc, argv, "epqrtf:")) != EOF) {
X			switch(c) {
X			case 'e':
X			case 'p':
X			case 'q':
X			case 'r':
X			case 'f':
X				reading = TRUE;
X				break;
X			case 't':
X				sending = TRUE;
X				break;
X			default:
X				usage();
X				return(1);
X			}
X		}
X	}
X
X	/* any arguments left over -> sending */
X	if(argc > optind) {
X		sending = TRUE;
X	}
X
X	if((reading == TRUE) && (sending == TRUE)) {
X		usage();
X		return(1);
X	}
X
X	if(sending == TRUE) {
X		argv[0] = SENDER;
X		for(i = 1, j = optind; j < argc; i++, j++) {
X			argv[i] = argv[j];
X		}
X		argv[i] = NULL;
X	} else {
X		argv[0] = READER;
X	}
X
X	(void) execvp(argv[0], argv);
X	(void) fprintf(stderr, "%s: execvp(\"%s\", argv) failed: ",
X		prog, argv[0]);
X	perror("");
X	return(1);
X}
X
Xvoid
Xusage()
X{
X	(void) fprintf(stderr, "usage:\t%s [ -epqr ] [ -f file ]\n", prog);
X	(void) fprintf(stderr, "\t%s [ -t ] persons\n", prog);
X}
@//E*O*F src/svbinmail.c//
if test 1749 -ne "`wc -c <'src/svbinmail.c'`"; then
    echo shar: error transmitting "'src/svbinmail.c'" '(should have been 1749 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/sysexits.h'" '(483 characters)'
if test -f 'src/sysexits.h' ; then 
  echo shar: will not over-write existing file "'src/sysexits.h'"
else
sed 's/^X//' >src/sysexits.h <<'@//E*O*F src/sysexits.h//'
X/*
X**	@(#)sysexits.h	2.1 (smail) 12/14/86
X*/
X
X# define EX_OK		0	/* successful termination */
X# define EX_USAGE	64	/* command line usage error */
X# define EX_NOHOST	68	/* host name unknown */
X# define EX_UNAVAILABLE	69	/* service unavailable */
X# define EX_SOFTWARE	70	/* internal software error */
X# define EX_OSFILE	72	/* critical OS file missing */
X# define EX_CANTCREAT	73	/* can't create (user) output file */
X# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
@//E*O*F src/sysexits.h//
if test 483 -ne "`wc -c <'src/sysexits.h'`"; then
    echo shar: error transmitting "'src/sysexits.h'" '(should have been 483 characters)'
fi
fi # end of overwriting check
echo shar: "End of shell archive."
exit 0



More information about the Mod.sources mailing list