Sendmail source for the 3B1/7300 (part 6/8)

David H. Brierley dave at galaxia.Newport.RI.US
Sat Feb 25 12:29:23 AEST 1989


----- cut here and feed to /bin/sh -----
#! /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 8)."
# Contents:  src/queue.c src/sendmail.h
# Wrapped by dave at galaxia on Fri Feb 24 20:24:09 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/queue.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/queue.c'\"
else
echo shar: Extracting \"'src/queue.c'\" \(20282 characters\)
sed "s/^X//" >'src/queue.c' <<'END_OF_FILE'
X/*
X**  Sendmail
X**  Copyright (c) 1983  Eric P. Allman
X**  Berkeley, California
X**
X**  Copyright (c) 1983 Regents of the University of California.
X**  All rights reserved.  The Berkeley software License Agreement
X**  specifies the terms and conditions for redistribution.
X*/
X
X
X# include "sendmail.h"
X# include <sys/stat.h>
X# include <dirent.h>
X# include <signal.h>
X# include <errno.h>
X
X# ifndef QUEUE
X# ifndef lint
Xstatic char	SccsId[] = "@(#)queue.c	5.22 (Berkeley) 10/14/86	(no queueing)";
X# endif not lint
X# else QUEUE
X
X# ifndef lint
Xstatic char	SccsId[] = "@(#)queue.c	5.22 (Berkeley) 10/14/86";
X# endif not lint
X
X/*
X**  Work queue.
X*/
X
Xstruct work
X{
X	char		*w_name;	/* name of control file */
X	long		w_pri;		/* priority of message, see below */
X	time_t		w_ctime;	/* creation time of message */
X	struct work	*w_next;	/* next in queue */
X};
X
Xtypedef struct work	WORK;
X
XWORK	*WorkQ;			/* queue of things to be done */
X/*
X**  QUEUEUP -- queue a message up for future transmission.
X**
X**	Parameters:
X**		e -- the envelope to queue up.
X**		queueall -- if TRUE, queue all addresses, rather than
X**			just those with the QQUEUEUP flag set.
X**		announce -- if TRUE, tell when you are queueing up.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		The current request are saved in a control file.
X*/
X
Xqueueup(e, queueall, announce)
X	register ENVELOPE *e;
X	bool queueall;
X	bool announce;
X{
X	char *tf;
X	char *qf;
X	char buf[MAXLINE];
X	register FILE *tfp;
X	register HDR *h;
X	register ADDRESS *q;
X	MAILER nullmailer;
X
X	/*
X	**  Create control file.
X	*/
X
X	tf = newstr(queuename(e, 't'));
X	tfp = fopen(tf, "w");
X	if (tfp == NULL)
X	{
X		syserr("queueup: cannot create temp file %s", tf);
X		return;
X	}
X	(void) chmod(tf, FileMode);
X
X# ifdef DEBUG
X	if (tTd(40, 1))
X		printf("queueing %s\n", e->e_id);
X# endif DEBUG
X
X	/*
X	**  If there is no data file yet, create one.
X	*/
X
X	if (e->e_df == NULL)
X	{
X		register FILE *dfp;
X		extern putbody();
X
X		e->e_df = newstr(queuename(e, 'd'));
X		dfp = fopen(e->e_df, "w");
X		if (dfp == NULL)
X		{
X			syserr("queueup: cannot create %s", e->e_df);
X			(void) fclose(tfp);
X			return;
X		}
X		(void) chmod(e->e_df, FileMode);
X		(*e->e_putbody)(dfp, ProgMailer, e);
X		(void) fclose(dfp);
X		e->e_putbody = putbody;
X	}
X
X	/*
X	**  Output future work requests.
X	**	Priority and creation time should be first, since
X	**	they are required by orderq.
X	*/
X
X	/* output message priority */
X	fprintf(tfp, "P%ld\n", e->e_msgpriority);
X
X	/* output creation time */
X	fprintf(tfp, "T%ld\n", e->e_ctime);
X
X	/* output name of data file */
X	fprintf(tfp, "D%s\n", e->e_df);
X
X	/* message from envelope, if it exists */
X	if (e->e_message != NULL)
X		fprintf(tfp, "M%s\n", e->e_message);
X
X	/* output name of sender */
X	fprintf(tfp, "S%s\n", e->e_from.q_paddr);
X
X	/* output list of recipient addresses */
X	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
X	{
X		if (queueall ? !bitset(QDONTSEND, q->q_flags) :
X			       bitset(QQUEUEUP, q->q_flags))
X		{
X			fprintf(tfp, "R%s\n", q->q_paddr);
X			if (announce)
X			{
X				e->e_to = q->q_paddr;
X				message(Arpa_Info, "queued");
X				if (LogLevel > 4)
X					logdelivery("queued");
X				e->e_to = NULL;
X			}
X#ifdef DEBUG
X			if (tTd(40, 1))
X			{
X				printf("queueing ");
X				printaddr(q, FALSE);
X			}
X#endif DEBUG
X		}
X	}
X
X	/* output list of error recipients */
X	for (q = e->e_errorqueue; q != NULL; q = q->q_next)
X	{
X		if (!bitset(QDONTSEND, q->q_flags))
X			fprintf(tfp, "E%s\n", q->q_paddr);
X	}
X
X	/*
X	**  Output headers for this message.
X	**	Expand macros completely here.  Queue run will deal with
X	**	everything as absolute headers.
X	**		All headers that must be relative to the recipient
X	**		can be cracked later.
X	**	We set up a "null mailer" -- i.e., a mailer that will have
X	**	no effect on the addresses as they are output.
X	*/
X
X	bzero((char *) &nullmailer, sizeof nullmailer);
X	nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;
X	nullmailer.m_eol = "\n";
X
X	define('g', "\001f", e);
X	for (h = e->e_header; h != NULL; h = h->h_link)
X	{
X		extern bool bitzerop();
X
X		/* don't output null headers */
X		if (h->h_value == NULL || h->h_value[0] == '\0')
X			continue;
X
X		/* don't output resent headers on non-resent messages */
X		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
X			continue;
X
X		/* output this header */
X		fprintf(tfp, "H");
X
X		/* if conditional, output the set of conditions */
X		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
X		{
X			int j;
X
X			(void) putc('?', tfp);
X			for (j = '\0'; j <= '\177'; j++)
X				if (bitnset(j, h->h_mflags))
X					(void) putc(j, tfp);
X			(void) putc('?', tfp);
X		}
X
X		/* output the header: expand macros, convert addresses */
X		if (bitset(H_DEFAULT, h->h_flags))
X		{
X			(void) expand(h->h_value, buf, &buf[sizeof buf], e);
X			fprintf(tfp, "%s: %s\n", h->h_field, buf);
X		}
X		else if (bitset(H_FROM|H_RCPT, h->h_flags))
X		{
X			commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
X				 &nullmailer);
X		}
X		else
X			fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
X	}
X
X	/*
X	**  Clean up.
X	*/
X
X	(void) fclose(tfp);
X	qf = queuename(e, 'q');
X	if (tf != NULL)
X	{
X		(void) unlink(qf);
X		if (rename(tf, qf) < 0)
X			syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df);
X		errno = 0;
X	}
X
X# ifdef LOG
X	/* save log info */
X	if (LogLevel > 15)
X		syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
X# endif LOG
X}
X/*
X**  RUNQUEUE -- run the jobs in the queue.
X**
X**	Gets the stuff out of the queue in some presumably logical
X**	order and processes them.
X**
X**	Parameters:
X**		forkflag -- TRUE if the queue scanning should be done in
X**			a child process.  We double-fork so it is not our
X**			child and we don't have to clean up after it.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		runs things in the mail queue.
X*/
X
Xrunqueue(forkflag)
X	bool forkflag;
X{
X	extern bool shouldqueue();
X
X	/*
X	**  If no work will ever be selected, don't even bother reading
X	**  the queue.
X	*/
X
X	if (shouldqueue(-100000000L))
X	{
X		if (Verbose)
X			printf("Skipping queue run -- load average too high\n");
X
X		if (forkflag)
X			return;
X		finis();
X	}
X
X	/*
X	**  See if we want to go off and do other useful work.
X	*/
X
X	if (forkflag)
X	{
X		int pid;
X
X		pid = dofork();
X		if (pid != 0)
X		{
X			extern reapchild();
X
X			/* parent -- pick up intermediate zombie */
X#ifndef SIGCHLD
X			(void) waitfor(pid);
X#else SIGCHLD
X			(void) signal(SIGCHLD, reapchild);
X#endif SIGCHLD
X			if (QueueIntvl != 0)
X				(void) setevent(QueueIntvl, runqueue, TRUE);
X			return;
X		}
X		/* child -- double fork */
X#ifndef SIGCHLD
X		if (fork() != 0)
X			exit(EX_OK);
X#else SIGCHLD
X		(void) signal(SIGCHLD, SIG_DFL);
X#endif SIGCHLD
X	}
X
X	setproctitle("running queue");
X
X# ifdef LOG
X	if (LogLevel > 11)
X		syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
X# endif LOG
X
X	/*
X	**  Release any resources used by the daemon code.
X	*/
X
X# ifdef DAEMON
X	clrdaemon();
X# endif DAEMON
X
X	/*
X	**  Make sure the alias database is open.
X	*/
X
X	initaliases(AliasFile, FALSE);
X
X	/*
X	**  Start making passes through the queue.
X	**	First, read and sort the entire queue.
X	**	Then, process the work in that order.
X	**		But if you take too long, start over.
X	*/
X
X	/* order the existing work requests */
X	(void) orderq(FALSE);
X
X	/* process them once at a time */
X	while (WorkQ != NULL)
X	{
X		WORK *w = WorkQ;
X
X		WorkQ = WorkQ->w_next;
X		dowork(w);
X		free(w->w_name);
X		free((char *) w);
X	}
X
X	/* exit without the usual cleanup */
X	exit(ExitStat);
X}
X/*
X**  ORDERQ -- order the work queue.
X**
X**	Parameters:
X**		doall -- if set, include everything in the queue (even
X**			the jobs that cannot be run because the load
X**			average is too high).  Otherwise, exclude those
X**			jobs.
X**
X**	Returns:
X**		The number of request in the queue (not necessarily
X**		the number of requests in WorkQ however).
X**
X**	Side Effects:
X**		Sets WorkQ to the queue of available work, in order.
X*/
X
X# define NEED_P		001
X# define NEED_T		002
X
Xorderq(doall)
X	bool doall;
X{
X	register struct dirent *d;
X	register WORK *w;
X	DIR *f;
X	register int i;
X	WORK wlist[QUEUESIZE+1];
X	int wn = -1;
X	extern workcmpf();
X
X	/* clear out old WorkQ */
X	for (w = WorkQ; w != NULL; )
X	{
X		register WORK *nw = w->w_next;
X
X		WorkQ = nw;
X		free(w->w_name);
X		free((char *) w);
X		w = nw;
X	}
X
X	/* open the queue directory */
X	f = opendir(".");
X	if (f == NULL)
X	{
X		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
X		return (0);
X	}
X
X	/*
X	**  Read the work directory.
X	*/
X
X	while ((d = readdir(f)) != NULL)
X	{
X		FILE *cf;
X		char lbuf[MAXNAME];
X
X		/* is this an interesting entry? */
X		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
X			continue;
X
X		/* yes -- open control file (if not too many files) */
X		if (++wn >= QUEUESIZE)
X			continue;
X		cf = fopen(d->d_name, "r");
X		if (cf == NULL)
X		{
X			/* this may be some random person sending hir msgs */
X			/* syserr("orderq: cannot open %s", cbuf); */
X#ifdef DEBUG
X			if (tTd(41, 2))
X				printf("orderq: cannot open %s (%d)\n",
X					d->d_name, errno);
X#endif DEBUG
X			errno = 0;
X			wn--;
X			continue;
X		}
X		w = &wlist[wn];
X		w->w_name = newstr(d->d_name);
X
X		/* make sure jobs in creation don't clog queue */
X		w->w_pri = 0x7fffffff;
X		w->w_ctime = 0;
X
X		/* extract useful information */
X		i = NEED_P | NEED_T;
X		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
X		{
X			extern long atol();
X
X			switch (lbuf[0])
X			{
X			  case 'P':
X				w->w_pri = atol(&lbuf[1]);
X				i &= ~NEED_P;
X				break;
X
X			  case 'T':
X				w->w_ctime = atol(&lbuf[1]);
X				i &= ~NEED_T;
X				break;
X			}
X		}
X		(void) fclose(cf);
X
X		if (!doall && shouldqueue(w->w_pri))
X		{
X			/* don't even bother sorting this job in */
X			wn--;
X		}
X	}
X	(void) closedir(f);
X	wn++;
X
X	/*
X	**  Sort the work directory.
X	*/
X
X	qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
X
X	/*
X	**  Convert the work list into canonical form.
X	**	Should be turning it into a list of envelopes here perhaps.
X	*/
X
X	WorkQ = NULL;
X	for (i = min(wn, QUEUESIZE); --i >= 0; )
X	{
X		w = (WORK *) xalloc(sizeof *w);
X		w->w_name = wlist[i].w_name;
X		w->w_pri = wlist[i].w_pri;
X		w->w_ctime = wlist[i].w_ctime;
X		w->w_next = WorkQ;
X		WorkQ = w;
X	}
X
X# ifdef DEBUG
X	if (tTd(40, 1))
X	{
X		for (w = WorkQ; w != NULL; w = w->w_next)
X			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
X	}
X# endif DEBUG
X
X	return (wn);
X}
X/*
X**  WORKCMPF -- compare function for ordering work.
X**
X**	Parameters:
X**		a -- the first argument.
X**		b -- the second argument.
X**
X**	Returns:
X**		-1 if a < b
X**		 0 if a == b
X**		+1 if a > b
X**
X**	Side Effects:
X**		none.
X*/
X
Xworkcmpf(a, b)
X	register WORK *a;
X	register WORK *b;
X{
X	long pa = a->w_pri + a->w_ctime;
X	long pb = b->w_pri + b->w_ctime;
X
X	if (pa == pb)
X		return (0);
X	else if (pa > pb)
X		return (1);
X	else
X		return (-1);
X}
X/*
X**  DOWORK -- do a work request.
X**
X**	Parameters:
X**		w -- the work request to be satisfied.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		The work request is satisfied if possible.
X*/
X
Xdowork(w)
X	register WORK *w;
X{
X	register int i;
X	extern bool shouldqueue();
X
X# ifdef DEBUG
X	if (tTd(40, 1))
X		printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
X# endif DEBUG
X
X	/*
X	**  Ignore jobs that are too expensive for the moment.
X	*/
X
X	if (shouldqueue(w->w_pri))
X	{
X		if (Verbose)
X			printf("\nSkipping %s\n", w->w_name + 2);
X		return;
X	}
X
X	/*
X	**  Fork for work.
X	*/
X
X	if (ForkQueueRuns)
X	{
X		i = fork();
X		if (i < 0)
X		{
X			syserr("dowork: cannot fork");
X			return;
X		}
X	}
X	else
X	{
X		i = 0;
X	}
X
X	if (i == 0)
X	{
X		/*
X		**  CHILD
X		**	Lock the control file to avoid duplicate deliveries.
X		**		Then run the file as though we had just read it.
X		**	We save an idea of the temporary name so we
X		**		can recover on interrupt.
X		*/
X
X		/* set basic modes, etc. */
X		(void) alarm(0);
X		clearenvelope(CurEnv, FALSE);
X		QueueRun = TRUE;
X		ErrorMode = EM_MAIL;
X		CurEnv->e_id = &w->w_name[2];
X# ifdef LOG
X		if (LogLevel > 11)
X			syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
X			       getpid());
X# endif LOG
X
X		/* don't use the headers from sendmail.cf... */
X		CurEnv->e_header = NULL;
X
X		/* lock the control file during processing */
X		if (link(w->w_name, queuename(CurEnv, 'l')) < 0)
X		{
X			/* being processed by another queuer */
X# ifdef LOG
X			if (LogLevel > 4)
X				syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id);
X# endif LOG
X			if (ForkQueueRuns)
X				exit(EX_OK);
X			else
X				return;
X		}
X
X		/* do basic system initialization */
X		initsys();
X
X		/* read the queue control file */
X		readqf(CurEnv, TRUE);
X		CurEnv->e_flags |= EF_INQUEUE;
X		eatheader(CurEnv);
X
X		/* do the delivery */
X		if (!bitset(EF_FATALERRS, CurEnv->e_flags))
X			sendall(CurEnv, SM_DELIVER);
X
X		/* finish up and exit */
X		if (ForkQueueRuns)
X			finis();
X		else
X			dropenvelope(CurEnv);
X	}
X	else
X	{
X		/*
X		**  Parent -- pick up results.
X		*/
X
X		errno = 0;
X		(void) waitfor(i);
X	}
X}
X/*
X**  READQF -- read queue file and set up environment.
X**
X**	Parameters:
X**		e -- the envelope of the job to run.
X**		full -- if set, read in all information.  Otherwise just
X**			read in info needed for a queue print.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		cf is read and created as the current job, as though
X**		we had been invoked by argument.
X*/
X
Xreadqf(e, full)
X	register ENVELOPE *e;
X	bool full;
X{
X	char *qf;
X	register FILE *qfp;
X	char buf[MAXFIELD];
X	extern char *fgetfolded();
X	extern long atol();
X
X	/*
X	**  Read and process the file.
X	*/
X
X	qf = queuename(e, 'q');
X	qfp = fopen(qf, "r");
X	if (qfp == NULL)
X	{
X		syserr("readqf: no control file %s", qf);
X		return;
X	}
X	FileName = qf;
X	LineNumber = 0;
X	if (Verbose && full)
X		printf("\nRunning %s\n", e->e_id);
X	while (fgetfolded(buf, sizeof buf, qfp) != NULL)
X	{
X# ifdef DEBUG
X		if (tTd(40, 4))
X			printf("+++++ %s\n", buf);
X# endif DEBUG
X		switch (buf[0])
X		{
X		  case 'R':		/* specify recipient */
X			sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue);
X			break;
X
X		  case 'E':		/* specify error recipient */
X			sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue);
X			break;
X
X		  case 'H':		/* header */
X			if (full)
X				(void) chompheader(&buf[1], FALSE);
X			break;
X
X		  case 'M':		/* message */
X			e->e_message = newstr(&buf[1]);
X			break;
X
X		  case 'S':		/* sender */
X			setsender(newstr(&buf[1]));
X			break;
X
X		  case 'D':		/* data file name */
X			if (!full)
X				break;
X			e->e_df = newstr(&buf[1]);
X			e->e_dfp = fopen(e->e_df, "r");
X			if (e->e_dfp == NULL)
X				syserr("readqf: cannot open %s", e->e_df);
X			break;
X
X		  case 'T':		/* init time */
X			e->e_ctime = atol(&buf[1]);
X			break;
X
X		  case 'P':		/* message priority */
X			e->e_msgpriority = atol(&buf[1]) + WkTimeFact;
X			break;
X
X		  case '\0':		/* blank line; ignore */
X			break;
X
X		  default:
X			syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
X				LineNumber, buf);
X			break;
X		}
X	}
X
X	(void) fclose(qfp);
X	FileName = NULL;
X
X	/*
X	**  If we haven't read any lines, this queue file is empty.
X	**  Arrange to remove it without referencing any null pointers.
X	*/
X
X	if (LineNumber == 0)
X	{
X		errno = 0;
X		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
X	}
X}
X/*
X**  PRINTQUEUE -- print out a representation of the mail queue
X**
X**	Parameters:
X**		none.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		Prints a listing of the mail queue on the standard output.
X*/
X
Xprintqueue()
X{
X	register WORK *w;
X	FILE *f;
X	int nrequests;
X	char buf[MAXLINE];
X
X	/*
X	**  Read and order the queue.
X	*/
X
X	nrequests = orderq(TRUE);
X
X	/*
X	**  Print the work list that we have read.
X	*/
X
X	/* first see if there is anything */
X	if (nrequests <= 0)
X	{
X		printf("Mail queue is empty\n");
X		return;
X	}
X
X	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
X	if (nrequests > QUEUESIZE)
X		printf(", only %d printed", QUEUESIZE);
X	if (Verbose)
X		printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
X	else
X		printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
X	for (w = WorkQ; w != NULL; w = w->w_next)
X	{
X		struct stat st;
X		auto time_t submittime = 0;
X		long dfsize = -1;
X		char lf[20];
X		char message[MAXLINE];
X		extern bool shouldqueue();
X
X		f = fopen(w->w_name, "r");
X		if (f == NULL)
X		{
X			errno = 0;
X			continue;
X		}
X		printf("%7s", w->w_name + 2);
X		(void) strcpy(lf, w->w_name);
X		lf[0] = 'l';
X		if (stat(lf, &st) >= 0)
X			printf("*");
X		else if (shouldqueue(w->w_pri))
X			printf("X");
X		else
X			printf(" ");
X		errno = 0;
X
X		message[0] = '\0';
X		while (fgets(buf, sizeof buf, f) != NULL)
X		{
X			fixcrlf(buf, TRUE);
X			switch (buf[0])
X			{
X			  case 'M':	/* error message */
X				(void) strcpy(message, &buf[1]);
X				break;
X
X			  case 'S':	/* sender name */
X				if (Verbose)
X					printf("%8ld %10ld %.12s %.38s", dfsize,
X					    w->w_pri, ctime(&submittime) + 4,
X					    &buf[1]);
X				else
X					printf("%8ld %.16s %.45s", dfsize,
X					    ctime(&submittime), &buf[1]);
X				if (message[0] != '\0')
X					printf("\n\t\t (%.60s)", message);
X				break;
X
X			  case 'R':	/* recipient name */
X				if (Verbose)
X					printf("\n\t\t\t\t\t %.38s", &buf[1]);
X				else
X					printf("\n\t\t\t\t  %.45s", &buf[1]);
X				break;
X
X			  case 'T':	/* creation time */
X				submittime = atol(&buf[1]);
X				break;
X
X			  case 'D':	/* data file name */
X				if (stat(&buf[1], &st) >= 0)
X					dfsize = st.st_size;
X				break;
X			}
X		}
X		if (submittime == (time_t) 0)
X			printf(" (no control file)");
X		printf("\n");
X		(void) fclose(f);
X	}
X}
X
X# endif QUEUE
X/*
X**  QUEUENAME -- build a file name in the queue directory for this envelope.
X**
X**	Assigns an id code if one does not already exist.
X**	This code is very careful to avoid trashing existing files
X**	under any circumstances.
X**		We first create an nf file that is only used when
X**		assigning an id.  This file is always empty, so that
X**		we can never accidently truncate an lf file.
X**
X**	Parameters:
X**		e -- envelope to build it in/from.
X**		type -- the file type, used as the first character
X**			of the file name.
X**
X**	Returns:
X**		a pointer to the new file name (in a static buffer).
X**
X**	Side Effects:
X**		Will create the lf and qf files if no id code is
X**		already assigned.  This will cause the envelope
X**		to be modified.
X*/
X
Xchar *
Xqueuename(e, type)
X	register ENVELOPE *e;
X	char type;
X{
X	static char buf[MAXNAME];
X	static int pid = -1;
X	char c1 = 'A';
X	char c2 = 'A';
X
X	if (e->e_id == NULL)
X	{
X		char qf[20];
X		char nf[20];
X		char lf[20];
X
X		/* find a unique id */
X		if (pid != getpid())
X		{
X			/* new process -- start back at "AA" */
X			pid = getpid();
X			c1 = 'A';
X			c2 = 'A' - 1;
X		}
X		(void) sprintf(qf, "qfAA%05d", pid);
X		(void) strcpy(lf, qf);
X		lf[0] = 'l';
X		(void) strcpy(nf, qf);
X		nf[0] = 'n';
X
X		while (c1 < '~' || c2 < 'Z')
X		{
X			int i;
X
X			if (c2 >= 'Z')
X			{
X				c1++;
X				c2 = 'A' - 1;
X			}
X			lf[2] = nf[2] = qf[2] = c1;
X			lf[3] = nf[3] = qf[3] = ++c2;
X# ifdef DEBUG
X			if (tTd(7, 20))
X				printf("queuename: trying \"%s\"\n", nf);
X# endif DEBUG
X
X# ifdef QUEUE
X			if (access(lf, 0) >= 0 || access(qf, 0) >= 0)
X				continue;
X			errno = 0;
X			i = creat(nf, FileMode);
X			if (i < 0)
X			{
X				(void) unlink(nf);	/* kernel bug */
X				continue;
X			}
X			(void) close(i);
X			i = link(nf, lf);
X			(void) unlink(nf);
X			if (i < 0)
X				continue;
X			if (link(lf, qf) >= 0)
X				break;
X			(void) unlink(lf);
X# else QUEUE
X			if (close(creat(qf, FileMode)) >= 0)
X				break;
X# endif QUEUE
X		}
X		if (c1 >= '~' && c2 >= 'Z')
X		{
X			syserr("queuename: Cannot create \"%s\" in \"%s\"",
X				qf, QueueDir);
X			exit(EX_OSERR);
X		}
X		e->e_id = newstr(&qf[2]);
X		define('i', e->e_id, e);
X# ifdef DEBUG
X		if (tTd(7, 1))
X			printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
X# ifdef LOG
X		if (LogLevel > 16)
X			syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
X# endif LOG
X# endif DEBUG
X	}
X
X	if (type == '\0')
X		return (NULL);
X	(void) sprintf(buf, "%cf%s", type, e->e_id);
X# ifdef DEBUG
X	if (tTd(7, 2))
X		printf("queuename: %s\n", buf);
X# endif DEBUG
X	return (buf);
X}
X/*
X**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
X**
X**	Parameters:
X**		e -- the envelope to unlock.
X**
X**	Returns:
X**		none
X**
X**	Side Effects:
X**		unlocks the queue for `e'.
X*/
X
Xunlockqueue(e)
X	ENVELOPE *e;
X{
X	/* remove the transcript */
X#ifdef DEBUG
X# ifdef LOG
X	if (LogLevel > 19)
X		syslog(LOG_DEBUG, "%s: unlock", e->e_id);
X# endif LOG
X	if (!tTd(51, 4))
X#endif DEBUG
X		xunlink(queuename(e, 'x'));
X
X# ifdef QUEUE
X	/* last but not least, remove the lock */
X	xunlink(queuename(e, 'l'));
X# endif QUEUE
X}
END_OF_FILE
if test 20282 -ne `wc -c <'src/queue.c'`; then
    echo shar: \"'src/queue.c'\" unpacked with wrong size!
fi
# end of 'src/queue.c'
fi
if test -f 'src/sendmail.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/sendmail.h'\"
else
echo shar: Extracting \"'src/sendmail.h'\" \(19799 characters\)
sed "s/^X//" >'src/sendmail.h' <<'END_OF_FILE'
X/*
X**  Sendmail
X**  Copyright (c) 1983  Eric P. Allman
X**  Berkeley, California
X**
X**  Copyright (c) 1983 Regents of the University of California.
X**  All rights reserved.  The Berkeley software License Agreement
X**  specifies the terms and conditions for redistribution.
X**
X**	@(#)sendmail.h	5.10 (Berkeley) 10/14/86
X*/
X
X/*
X**  SENDMAIL.H -- Global definitions for sendmail.
X*/
X
X
X
X# ifdef _DEFINE
X# define EXTERN
X# ifndef lint
Xstatic char SmailSccsId[] =	"@(#)sendmail.h	5.10		10/14/86";
X# endif lint
X# else  _DEFINE
X# define EXTERN extern
X# endif _DEFINE
X
X# include <stdio.h>
X# include <ctype.h>
X# include <setjmp.h>
X# include "conf.h"
X# include "useful.h"
X
X# ifdef LOG
X# include <sys/syslog.h>
X# endif LOG
X
X# ifdef DAEMON
X# include <sys/socket.h>
X# include <netinet/in.h>
X# endif DAEMON
X
X
X# define PSBUFSIZE	(MAXNAME + MAXATOM)	/* size of prescan buffer */
X
X
X/*
X**  Data structure for bit maps.
X**
X**	Each bit in this map can be referenced by an ascii character.
X**	This is 128 possible bits, or 12 8-bit bytes.
X*/
X
X#define BITMAPBYTES	16	/* number of bytes in a bit map */
X#define BYTEBITS	8	/* number of bits in a byte */
X
X/* internal macros */
X#define _BITWORD(bit)	(bit / (BYTEBITS * sizeof (int)))
X#define _BITBIT(bit)	(1 << (bit % (BYTEBITS * sizeof (int))))
X
Xtypedef int	BITMAP[BITMAPBYTES / sizeof (int)];
X
X/* test bit number N */
X#define bitnset(bit, map)	((map)[_BITWORD(bit)] & _BITBIT(bit))
X
X/* set bit number N */
X#define setbitn(bit, map)	(map)[_BITWORD(bit)] |= _BITBIT(bit)
X
X/* clear bit number N */
X#define clrbitn(bit, map)	(map)[_BITWORD(bit)] &= ~_BITBIT(bit)
X
X/* clear an entire bit map */
X#define clrbitmap(map)		bzero((char *) map, BITMAPBYTES)
X/*
X**  Address structure.
X**	Addresses are stored internally in this structure.
X*/
X
Xstruct address
X{
X	char		*q_paddr;	/* the printname for the address */
X	char		*q_user;	/* user name */
X	char		*q_host;	/* host name */
X	struct mailer	*q_mailer;	/* mailer to use */
X	u_short		q_flags;	/* status flags, see below */
X	short		q_uid;		/* user-id of receiver (if known) */
X	short		q_gid;		/* group-id of receiver (if known) */
X	char		*q_home;	/* home dir (local mailer only) */
X	char		*q_fullname;	/* full name if known */
X	struct address	*q_next;	/* chain */
X	struct address	*q_alias;	/* address this results from */
X	struct address	*q_tchain;	/* temporary use chain */
X	time_t		q_timeout;	/* timeout for this address */
X};
X
Xtypedef struct address ADDRESS;
X
X# define QDONTSEND	000001	/* don't send to this address */
X# define QBADADDR	000002	/* this address is verified bad */
X# define QGOODUID	000004	/* the q_uid q_gid fields are good */
X# define QPRIMARY	000010	/* set from argv */
X# define QQUEUEUP	000020	/* queue for later transmission */
X/*
X**  Mailer definition structure.
X**	Every mailer known to the system is declared in this
X**	structure.  It defines the pathname of the mailer, some
X**	flags associated with it, and the argument vector to
X**	pass to it.  The flags are defined in conf.c
X**
X**	The argument vector is expanded before actual use.  All
X**	words except the first are passed through the macro
X**	processor.
X*/
X
Xstruct mailer
X{
X	char	*m_name;	/* symbolic name of this mailer */
X	char	*m_mailer;	/* pathname of the mailer to use */
X	BITMAP	m_flags;	/* status flags, see below */
X	short	m_mno;		/* mailer number internally */
X	char	**m_argv;	/* template argument vector */
X	short	m_s_rwset;	/* rewriting set for sender addresses */
X	short	m_r_rwset;	/* rewriting set for recipient addresses */
X	char	*m_eol;		/* end of line string */
X	long	m_maxsize;	/* size limit on message to this mailer */
X};
X
Xtypedef struct mailer	MAILER;
X
X/* bits for m_flags */
X# define M_CANONICAL	'C'	/* make addresses canonical "u at dom" */
X# define M_EXPENSIVE	'e'	/* it costs to use this mailer.... */
X# define M_ESCFROM	'E'	/* escape From lines to >From */
X# define M_FOPT		'f'	/* mailer takes picky -f flag */
X# define M_HST_UPPER	'h'	/* preserve host case distinction */
X# define M_INTERNAL	'I'	/* SMTP to another sendmail site */
X# define M_LOCAL	'l'	/* delivery is to this host */
X# define M_LIMITS	'L'	/* must enforce SMTP line limits */
X# define M_MUSER	'm'	/* can handle multiple users at once */
X# define M_NHDR		'n'	/* don't insert From line */
X# define M_FROMPATH	'p'	/* use reverse-path in MAIL FROM: */
X# define M_ROPT		'r'	/* mailer takes picky -r flag */
X# define M_SECURE_PORT	'R'	/* try to send on a reserved TCP port */
X# define M_STRIPQ	's'	/* strip quote chars from user/host */
X# define M_RESTR	'S'	/* must be daemon to execute */
X# define M_USR_UPPER	'u'	/* preserve user case distinction */
X# define M_UGLYUUCP	'U'	/* this wants an ugly UUCP from line */
X# define M_XDOT		'X'	/* use hidden-dot algorithm */
X
XEXTERN MAILER	*Mailer[MAXMAILERS+1];
X
XEXTERN MAILER	*LocalMailer;		/* ptr to local mailer */
XEXTERN MAILER	*ProgMailer;		/* ptr to program mailer */
X/*
X**  Header structure.
X**	This structure is used internally to store header items.
X*/
X
Xstruct header
X{
X	char		*h_field;	/* the name of the field */
X	char		*h_value;	/* the value of that field */
X	struct header	*h_link;	/* the next header */
X	u_short		h_flags;	/* status bits, see below */
X	BITMAP		h_mflags;	/* m_flags bits needed */
X};
X
Xtypedef struct header	HDR;
X
X/*
X**  Header information structure.
X**	Defined in conf.c, this struct declares the header fields
X**	that have some magic meaning.
X*/
X
Xstruct hdrinfo
X{
X	char	*hi_field;	/* the name of the field */
X	u_short	hi_flags;	/* status bits, see below */
X};
X
Xextern struct hdrinfo	HdrInfo[];
X
X/* bits for h_flags and hi_flags */
X# define H_EOH		00001	/* this field terminates header */
X# define H_RCPT		00002	/* contains recipient addresses */
X# define H_DEFAULT	00004	/* if another value is found, drop this */
X# define H_RESENT	00010	/* this address is a "Resent-..." address */
X# define H_CHECK	00020	/* check h_mflags against m_flags */
X# define H_ACHECK	00040	/* ditto, but always (not just default) */
X# define H_FORCE	00100	/* force this field, even if default */
X# define H_TRACE	00200	/* this field contains trace information */
X# define H_FROM		00400	/* this is a from-type field */
X# define H_VALID	01000	/* this field has a validated value */
X/*
X**  Envelope structure.
X**	This structure defines the message itself.  There is usually
X**	only one of these -- for the message that we originally read
X**	and which is our primary interest -- but other envelopes can
X**	be generated during processing.  For example, error messages
X**	will have their own envelope.
X*/
X
Xstruct envelope
X{
X	HDR		*e_header;	/* head of header list */
X	long		e_msgpriority;	/* adjusted priority of this message */
X	time_t		e_ctime;	/* time message appeared in the queue */
X	char		*e_to;		/* the target person */
X	char		*e_receiptto;	/* return receipt address */
X	ADDRESS		e_from;		/* the person it is from */
X	char		**e_fromdomain;	/* the domain part of the sender */
X	ADDRESS		*e_sendqueue;	/* list of message recipients */
X	ADDRESS		*e_errorqueue;	/* the queue for error responses */
X	long		e_msgsize;	/* size of the message in bytes */
X	int		e_nrcpts;	/* number of recipients */
X	short		e_class;	/* msg class (priority, junk, etc.) */
X	short		e_flags;	/* flags, see below */
X	short		e_hopcount;	/* number of times processed */
X	int		(*e_puthdr)();	/* function to put header of message */
X	int		(*e_putbody)();	/* function to put body of message */
X	struct envelope	*e_parent;	/* the message this one encloses */
X	struct envelope *e_sibling;	/* the next envelope of interest */
X	char		*e_df;		/* location of temp file */
X	FILE		*e_dfp;		/* temporary file */
X	char		*e_id;		/* code for this entry in queue */
X	FILE		*e_xfp;		/* transcript file */
X	char		*e_message;	/* error message */
X	char		*e_macro[128];	/* macro definitions */
X};
X
Xtypedef struct envelope	ENVELOPE;
X
X/* values for e_flags */
X#define EF_OLDSTYLE	000001		/* use spaces (not commas) in hdrs */
X#define EF_INQUEUE	000002		/* this message is fully queued */
X#define EF_TIMEOUT	000004		/* this message is too old */
X#define EF_CLRQUEUE	000010		/* disk copy is no longer needed */
X#define EF_SENDRECEIPT	000020		/* send a return receipt */
X#define EF_FATALERRS	000040		/* fatal errors occured */
X#define EF_KEEPQUEUE	000100		/* keep queue files always */
X#define EF_RESPONSE	000200		/* this is an error or return receipt */
X#define EF_RESENT	000400		/* this message is being forwarded */
X
XEXTERN ENVELOPE	*CurEnv;	/* envelope currently being processed */
X/*
X**  Message priority classes.
X**
X**	The message class is read directly from the Priority: header
X**	field in the message.
X**
X**	CurEnv->e_msgpriority is the number of bytes in the message plus
X**	the creation time (so that jobs ``tend'' to be ordered correctly),
X**	adjusted by the message class, the number of recipients, and the
X**	amount of time the message has been sitting around.  This number
X**	is used to order the queue.  Higher values mean LOWER priority.
X**
X**	Each priority class point is worth WkClassFact priority points;
X**	each recipient is worth WkRecipFact priority points.  Each time
X**	we reprocess a message the priority is adjusted by WkTimeFact.
X**	WkTimeFact should normally decrease the priority so that jobs
X**	that have historically failed will be run later; thanks go to
X**	Jay Lepreau at Utah for pointing out the error in my thinking.
X**
X**	The "class" is this number, unadjusted by the age or size of
X**	this message.  Classes with negative representations will have
X**	error messages thrown away if they are not local.
X*/
X
Xstruct priority
X{
X	char	*pri_name;	/* external name of priority */
X	int	pri_val;	/* internal value for same */
X};
X
XEXTERN struct priority	Priorities[MAXPRIORITIES];
XEXTERN int		NumPriorities;	/* pointer into Priorities */
X/*
X**  Rewrite rules.
X*/
X
Xstruct rewrite
X{
X	char	**r_lhs;	/* pattern match */
X	char	**r_rhs;	/* substitution value */
X	struct rewrite	*r_next;/* next in chain */
X};
X
XEXTERN struct rewrite	*RewriteRules[MAXRWSETS];
X
X/*
X**  Special characters in rewriting rules.
X**	These are used internally only.
X**	The COND* rules are actually used in macros rather than in
X**		rewriting rules, but are given here because they
X**		cannot conflict.
X*/
X
X/* left hand side items */
X# define MATCHZANY	'\020'	/* match zero or more tokens */
X# define MATCHANY	'\021'	/* match one or more tokens */
X# define MATCHONE	'\022'	/* match exactly one token */
X# define MATCHCLASS	'\023'	/* match one token in a class */
X# define MATCHNCLASS	'\024'	/* match anything not in class */
X# define MATCHREPL	'\025'	/* replacement on RHS for above */
X
X/* right hand side items */
X# define CANONNET	'\026'	/* canonical net, next token */
X# define CANONHOST	'\027'	/* canonical host, next token */
X# define CANONUSER	'\030'	/* canonical user, next N tokens */
X# define CALLSUBR	'\031'	/* call another rewriting set */
X
X/* conditionals in macros */
X# define CONDIF		'\032'	/* conditional if-then */
X# define CONDELSE	'\033'	/* conditional else */
X# define CONDFI		'\034'	/* conditional fi */
X
X/* bracket characters for host name lookup */
X# define HOSTBEGIN	'\035'	/* hostname lookup begin */
X# define HOSTEND	'\036'	/* hostname lookup end */
X
X/* \001 is also reserved as the macro expansion character */
X/*
X**  Information about hosts that we have looked up recently.
X**
X**	This stuff is 4.2/3bsd specific.
X*/
X
X# ifdef DAEMON
X# ifdef VMUNIX
X
X# define HOSTINFO	struct hostinfo
X
XHOSTINFO
X{
X	char		*ho_name;	/* name of this host */
X	struct in_addr	ho_inaddr;	/* internet address */
X	short		ho_flags;	/* flag bits, see below */
X	short		ho_errno;	/* error number on last connection */
X	short		ho_exitstat;	/* exit status from last connection */
X};
X
X
X/* flag bits */
X#define HOF_VALID	00001		/* this entry is valid */
X
X# endif VMUNIX
X# endif DAEMON
X/*
X**  Symbol table definitions
X*/
X
Xstruct symtab
X{
X	char		*s_name;	/* name to be entered */
X	char		s_type;		/* general type (see below) */
X	struct symtab	*s_next;	/* pointer to next in chain */
X	union
X	{
X		BITMAP		sv_class;	/* bit-map of word classes */
X		ADDRESS		*sv_addr;	/* pointer to address header */
X		MAILER		*sv_mailer;	/* pointer to mailer */
X		char		*sv_alias;	/* alias */
X# ifdef HOSTINFO
X		HOSTINFO	sv_host;	/* host information */
X# endif HOSTINFO
X	}	s_value;
X};
X
Xtypedef struct symtab	STAB;
X
X/* symbol types */
X# define ST_UNDEF	0	/* undefined type */
X# define ST_CLASS	1	/* class map */
X# define ST_ADDRESS	2	/* an address in parsed format */
X# define ST_MAILER	3	/* a mailer header */
X# define ST_ALIAS	4	/* an alias */
X# define ST_HOST	5	/* host information */
X
X# define s_class	s_value.sv_class
X# define s_address	s_value.sv_addr
X# define s_mailer	s_value.sv_mailer
X# define s_alias	s_value.sv_alias
X# define s_host		s_value.sv_host
X
Xextern STAB	*stab();
X
X/* opcodes to stab */
X# define ST_FIND	0	/* find entry */
X# define ST_ENTER	1	/* enter if not there */
X/*
X**  STRUCT EVENT -- event queue.
X**
X**	Maintained in sorted order.
X**
X**	We store the pid of the process that set this event to insure
X**	that when we fork we will not take events intended for the parent.
X*/
X
Xstruct event
X{
X	time_t		ev_time;	/* time of the function call */
X	int		(*ev_func)();	/* function to call */
X	int		ev_arg;		/* argument to ev_func */
X	int		ev_pid;		/* pid that set this event */
X	struct event	*ev_link;	/* link to next item */
X};
X
Xtypedef struct event	EVENT;
X
XEXTERN EVENT	*EventQueue;		/* head of event queue */
X/*
X**  Operation, send, and error modes
X**
X**	The operation mode describes the basic operation of sendmail.
X**	This can be set from the command line, and is "send mail" by
X**	default.
X**
X**	The send mode tells how to send mail.  It can be set in the
X**	configuration file.  It's setting determines how quickly the
X**	mail will be delivered versus the load on your system.  If the
X**	-v (verbose) flag is given, it will be forced to SM_DELIVER
X**	mode.
X**
X**	The error mode tells how to return errors.
X*/
X
XEXTERN char	OpMode;		/* operation mode, see below */
X
X#define MD_DELIVER	'm'		/* be a mail sender */
X#define MD_ARPAFTP	'a'		/* old-style arpanet protocols */
X#define MD_SMTP		's'		/* run SMTP on standard input */
X#define MD_DAEMON	'd'		/* run as a daemon */
X#define MD_VERIFY	'v'		/* verify: don't collect or deliver */
X#define MD_TEST		't'		/* test mode: resolve addrs only */
X#define MD_INITALIAS	'i'		/* initialize alias database */
X#define MD_PRINT	'p'		/* print the queue */
X#define MD_FREEZE	'z'		/* freeze the configuration file */
X
X
XEXTERN char	SendMode;	/* send mode, see below */
X
X#define SM_DELIVER	'i'		/* interactive delivery */
X#define SM_QUICKD	'j'		/* deliver w/o queueing */
X#define SM_FORK		'b'		/* deliver in background */
X#define SM_QUEUE	'q'		/* queue, don't deliver */
X#define SM_VERIFY	'v'		/* verify only (used internally) */
X
X/* used only as a parameter to sendall */
X#define SM_DEFAULT	'\0'		/* unspecified, use SendMode */
X
X
XEXTERN char	ErrorMode;	/* error mode, see below */
X
X#define EM_PRINT	'p'		/* print errors */
X#define EM_MAIL		'm'		/* mail back errors */
X#define EM_WRITE	'w'		/* write back errors */
X#define EM_BERKNET	'e'		/* special berknet processing */
X#define EM_QUIET	'q'		/* don't print messages (stat only) */
X
X/* offset used to issure that the error messages for name server error
X * codes are unique.
X */
X#define	MAX_ERRNO	100
X/*
X**  Global variables.
X*/
X
XEXTERN bool	FromFlag;	/* if set, "From" person is explicit */
XEXTERN bool	NoAlias;	/* if set, don't do any aliasing */
XEXTERN bool	ForceMail;	/* if set, mail even if already got a copy */
XEXTERN bool	MeToo;		/* send to the sender also */
XEXTERN bool	IgnrDot;	/* don't let dot end messages */
XEXTERN bool	SaveFrom;	/* save leading "From" lines */
XEXTERN bool	Verbose;	/* set if blow-by-blow desired */
XEXTERN bool	GrabTo;		/* if set, get recipients from msg */
XEXTERN bool	NoReturn;	/* don't return letter to sender */
XEXTERN bool	SuprErrs;	/* set if we are suppressing errors */
XEXTERN bool	QueueRun;	/* currently running message from the queue */
XEXTERN bool	HoldErrs;	/* only output errors to transcript */
XEXTERN bool	NoConnect;	/* don't connect to non-local mailers */
XEXTERN bool	SuperSafe;	/* be extra careful, even if expensive */
XEXTERN bool	ForkQueueRuns;	/* fork for each job when running the queue */
XEXTERN bool	AutoRebuild;	/* auto-rebuild the alias database as needed */
XEXTERN bool	CheckAliases;	/* parse addresses during newaliases */
XEXTERN int	SafeAlias;	/* minutes to wait until @:@ in alias file */
XEXTERN time_t	TimeOut;	/* time until timeout */
XEXTERN FILE	*InChannel;	/* input connection */
XEXTERN FILE	*OutChannel;	/* output connection */
XEXTERN int	RealUid;	/* when Daemon, real uid of caller */
XEXTERN int	RealGid;	/* when Daemon, real gid of caller */
XEXTERN int	DefUid;		/* default uid to run as */
XEXTERN int	DefGid;		/* default gid to run as */
XEXTERN int	OldUmask;	/* umask when sendmail starts up */
XEXTERN int	Errors;		/* set if errors (local to single pass) */
XEXTERN int	ExitStat;	/* exit status code */
XEXTERN int	AliasLevel;	/* depth of aliasing */
XEXTERN int	MotherPid;	/* proc id of parent process */
XEXTERN int	LineNumber;	/* line number in current input */
XEXTERN time_t	ReadTimeout;	/* timeout on reads */
XEXTERN int	LogLevel;	/* level of logging to perform */
XEXTERN int	FileMode;	/* mode on files */
XEXTERN int	QueueLA;	/* load average starting forced queueing */
XEXTERN int	RefuseLA;	/* load average refusing connections are */
XEXTERN int	QueueFactor;	/* slope of queue function */
XEXTERN time_t	QueueIntvl;	/* intervals between running the queue */
XEXTERN char	*AliasFile;	/* location of alias file */
XEXTERN char	*HelpFile;	/* location of SMTP help file */
XEXTERN char	*StatFile;	/* location of statistics summary */
XEXTERN char	*QueueDir;	/* location of queue directory */
XEXTERN char	*FileName;	/* name to print on error messages */
XEXTERN char	*SmtpPhase;	/* current phase in SMTP processing */
XEXTERN char	*MyHostName;	/* name of this host for SMTP messages */
XEXTERN char	*RealHostName;	/* name of host we are talking to */
XEXTERN char	*CurHostName;	/* current host we are dealing with */
XEXTERN jmp_buf	TopFrame;	/* branch-to-top-of-loop-on-error frame */
XEXTERN bool	QuickAbort;	/*  .... but only if we want a quick abort */
Xextern char	*ConfFile;	/* location of configuration file [conf.c] */
Xextern char	*FreezeFile;	/* location of frozen memory image [conf.c] */
Xextern char	Arpa_Info[];	/* the reply code for Arpanet info [conf.c] */
Xextern ADDRESS	NullAddress;	/* a null (template) address [main.c] */
XEXTERN char	SpaceSub;	/* substitution for <lwsp> */
XEXTERN int	WkClassFact;	/* multiplier for message class -> priority */
XEXTERN int	WkRecipFact;	/* multiplier for # of recipients -> priority */
XEXTERN int	WkTimeFact;	/* priority offset each time this job is run */
XEXTERN int	CheckPointLimit;	/* deliveries before checkpointing */
XEXTERN int	Nmx;			/* number of MX RRs */
XEXTERN char	*PostMasterCopy;	/* address to get errs cc's */
XEXTERN char	*MxHosts[MAXMXHOSTS+1];	/* for MX RRs */
XEXTERN char	*TrustedUsers[MAXTRUST+1];	/* list of trusted users */
XEXTERN char	*UserEnviron[MAXUSERENVIRON+1];	/* saved user environment */
X/*
X**  Trace information
X*/
X
X/* trace vector and macros for debugging flags */
XEXTERN u_char	tTdvect[100];
X# define tTd(flag, level)	(tTdvect[flag] >= level)
X# define tTdlevel(flag)		(tTdvect[flag])
X/*
X**  Miscellaneous information.
X*/
X
X# include	<sysexits.h>
X
X
X/*
X**  Some in-line functions
X*/
X
X/* set exit status */
X#define setstat(s)	{ \
X				if (ExitStat == EX_OK || ExitStat == EX_TEMPFAIL) \
X					ExitStat = s; \
X			}
X
X/* make a copy of a string */
X#define newstr(s)	strcpy(xalloc(strlen(s) + 1), s)
X
X#define STRUCTCOPY(s, d)	d = s
X
X
X/*
X**  Declarations of useful functions
X*/
X
Xextern ADDRESS	*parseaddr();
Xextern char	*xalloc();
Xextern bool	sameaddr();
Xextern FILE	*dfopen();
Xextern EVENT	*setevent();
Xextern char	*sfgets();
Xextern char	*queuename();
Xextern time_t	curtime();
END_OF_FILE
if test 19799 -ne `wc -c <'src/sendmail.h'`; then
    echo shar: \"'src/sendmail.h'\" unpacked with wrong size!
fi
# end of 'src/sendmail.h'
fi
echo shar: End of archive 6 \(of 8\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 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
-- 
David H. Brierley
Home: dave at galaxia.Newport.RI.US   {rayssd,xanth,lazlo,jclyde}!galaxia!dave
Work: dhb at rayssd.ray.com           {sun,decuac,gatech,necntc,ukma}!rayssd!dhb



More information about the Unix-pc.sources mailing list