queue.c revision 42575
14Srgrimes/*
24Srgrimes * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
34Srgrimes * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
44Srgrimes * Copyright (c) 1988, 1993
54Srgrimes *	The Regents of the University of California.  All rights reserved.
64Srgrimes *
74Srgrimes * By using this file, you agree to the terms and conditions set
84Srgrimes * forth in the LICENSE file which can be found at the top level of
94Srgrimes * the sendmail distribution.
104Srgrimes *
114Srgrimes */
124Srgrimes
134Srgrimes# include "sendmail.h"
144Srgrimes
154Srgrimes#ifndef lint
164Srgrimes#if QUEUE
174Srgrimesstatic char sccsid[] = "@(#)queue.c	8.210 (Berkeley) 10/15/1998 (with queueing)";
184Srgrimes#else
194Srgrimesstatic char sccsid[] = "@(#)queue.c	8.210 (Berkeley) 10/15/1998 (without queueing)";
204Srgrimes#endif
214Srgrimes#endif /* not lint */
224Srgrimes
234Srgrimes# include <errno.h>
244Srgrimes# include <dirent.h>
254Srgrimes
264Srgrimes# if QUEUE
274Srgrimes
284Srgrimes/*
294Srgrimes**  Work queue.
304Srgrimes*/
314Srgrimes
324Srgrimesstruct work
334Srgrimes{
344Srgrimes	char		*w_name;	/* name of control file */
354Srgrimes	char		*w_host;	/* name of recipient host */
364Srgrimes	bool		w_lock;		/* is message locked? */
374Srgrimes	bool		w_tooyoung;	/* is it too young to run? */
384Srgrimes	long		w_pri;		/* priority of message, see below */
394Srgrimes	time_t		w_ctime;	/* creation time of message */
404Srgrimes	struct work	*w_next;	/* next in queue */
414Srgrimes};
424Srgrimes
434Srgrimestypedef struct work	WORK;
444Srgrimes
454SrgrimesWORK	*WorkQ;			/* queue of things to be done */
464Srgrimes
474Srgrimes#define QF_VERSION	2	/* version number of this queue format */
484Srgrimes
494Srgrimesextern int orderq __P((bool));
504Srgrimes/*
514Srgrimes**  QUEUEUP -- queue a message up for future transmission.
524Srgrimes**
534Srgrimes**	Parameters:
544Srgrimes**		e -- the envelope to queue up.
554Srgrimes**		announce -- if TRUE, tell when you are queueing up.
564Srgrimes**
574Srgrimes**	Returns:
584Srgrimes**		none.
594Srgrimes**
604Srgrimes**	Side Effects:
614Srgrimes**		The current request are saved in a control file.
624Srgrimes**		The queue file is left locked.
634Srgrimes*/
644Srgrimes
654Srgrimesvoid
664Srgrimesqueueup(e, announce)
674Srgrimes	register ENVELOPE *e;
684Srgrimes	bool announce;
694Srgrimes{
704Srgrimes	char *qf;
714Srgrimes	register FILE *tfp;
724Srgrimes	register HDR *h;
734Srgrimes	register ADDRESS *q;
744Srgrimes	int fd;
754Srgrimes	int i;
764Srgrimes	bool newid;
774Srgrimes	register char *p;
784Srgrimes	MAILER nullmailer;
794Srgrimes	MCI mcibuf;
804Srgrimes	char tf[MAXQFNAME];
814Srgrimes	char buf[MAXLINE];
824Srgrimes	extern void printctladdr __P((ADDRESS *, FILE *));
834Srgrimes
844Srgrimes	/*
854Srgrimes	**  Create control file.
864Srgrimes	*/
874Srgrimes
884Srgrimes	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
894Srgrimes
904Srgrimes	/* if newid, queuename will create a locked qf file in e->lockfp */
914Srgrimes	strcpy(tf, queuename(e, 't'));
924Srgrimes	tfp = e->e_lockfp;
934Srgrimes	if (tfp == NULL)
944Srgrimes		newid = FALSE;
954Srgrimes
964Srgrimes	/* if newid, just write the qf file directly (instead of tf file) */
974Srgrimes	if (!newid)
984Srgrimes	{
994Srgrimes		/* get a locked tf file */
1004Srgrimes		for (i = 0; i < 128; i++)
1014Srgrimes		{
1024Srgrimes			fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
1034Srgrimes			if (fd < 0)
1044Srgrimes			{
1054Srgrimes				if (errno != EEXIST)
1064Srgrimes					break;
1074Srgrimes				if (LogLevel > 0 && (i % 32) == 0)
1084Srgrimes					sm_syslog(LOG_ALERT, e->e_id,
1094Srgrimes						"queueup: cannot create %s, uid=%d: %s",
1104Srgrimes						tf, geteuid(), errstring(errno));
1114Srgrimes			}
1124Srgrimes			else
1134Srgrimes			{
1144Srgrimes				if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
1154Srgrimes					break;
1164Srgrimes				else if (LogLevel > 0 && (i % 32) == 0)
1174Srgrimes					sm_syslog(LOG_ALERT, e->e_id,
1184Srgrimes						"queueup: cannot lock %s: %s",
1194Srgrimes						tf, errstring(errno));
1204Srgrimes				close(fd);
1214Srgrimes			}
1224Srgrimes
1234Srgrimes			if ((i % 32) == 31)
1244Srgrimes			{
1254Srgrimes				/* save the old temp file away */
1264Srgrimes				(void) rename(tf, queuename(e, 'T'));
1274Srgrimes			}
1284Srgrimes			else
1294Srgrimes				sleep(i % 32);
1304Srgrimes		}
1314Srgrimes		if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
1324Srgrimes		{
1334Srgrimes			printopenfds(TRUE);
1344Srgrimes			syserr("!queueup: cannot create queue temp file %s, uid=%d",
1354Srgrimes				tf, geteuid());
1364Srgrimes		}
1374Srgrimes	}
1384Srgrimes
1394Srgrimes	if (tTd(40, 1))
1404Srgrimes		printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id,
1414Srgrimes			newid ? " (new id)" : "");
1424Srgrimes	if (tTd(40, 3))
1434Srgrimes	{
1444Srgrimes		extern void printenvflags __P((ENVELOPE *));
1454Srgrimes
1464Srgrimes		printf("  e_flags=");
1474Srgrimes		printenvflags(e);
1484Srgrimes	}
1494Srgrimes	if (tTd(40, 32))
1504Srgrimes	{
1514Srgrimes		printf("  sendq=");
1524Srgrimes		printaddr(e->e_sendqueue, TRUE);
1534Srgrimes	}
1544Srgrimes	if (tTd(40, 9))
1554Srgrimes	{
1564Srgrimes		printf("  tfp=");
1574Srgrimes		dumpfd(fileno(tfp), TRUE, FALSE);
1584Srgrimes		printf("  lockfp=");
1594Srgrimes		if (e->e_lockfp == NULL)
1604Srgrimes			printf("NULL\n");
1614Srgrimes		else
1624Srgrimes			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1634Srgrimes	}
1644Srgrimes
1654Srgrimes	/*
1664Srgrimes	**  If there is no data file yet, create one.
1674Srgrimes	*/
1684Srgrimes
1694Srgrimes	if (!bitset(EF_HAS_DF, e->e_flags))
1704Srgrimes	{
1714Srgrimes		register FILE *dfp = NULL;
1724Srgrimes		char dfname[MAXQFNAME];
1734Srgrimes		struct stat stbuf;
1744Srgrimes
1754Srgrimes		strcpy(dfname, queuename(e, 'd'));
1764Srgrimes		fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
1774Srgrimes		if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
1784Srgrimes			syserr("!queueup: cannot create data temp file %s, uid=%d",
1794Srgrimes				dfname, geteuid());
1804Srgrimes		if (fstat(fd, &stbuf) < 0)
1814Srgrimes			e->e_dfino = -1;
1824Srgrimes		else
1834Srgrimes		{
1844Srgrimes			e->e_dfdev = stbuf.st_dev;
1854Srgrimes			e->e_dfino = stbuf.st_ino;
1864Srgrimes		}
1874Srgrimes		e->e_flags |= EF_HAS_DF;
1884Srgrimes		bzero(&mcibuf, sizeof mcibuf);
1894Srgrimes		mcibuf.mci_out = dfp;
1904Srgrimes		mcibuf.mci_mailer = FileMailer;
1914Srgrimes		(*e->e_putbody)(&mcibuf, e, NULL);
1924Srgrimes		(void) xfclose(dfp, "queueup dfp", e->e_id);
1934Srgrimes		e->e_putbody = putbody;
1944Srgrimes	}
1954Srgrimes
1964Srgrimes	/*
1974Srgrimes	**  Output future work requests.
1984Srgrimes	**	Priority and creation time should be first, since
1994Srgrimes	**	they are required by orderq.
2004Srgrimes	*/
2014Srgrimes
2024Srgrimes	/* output queue version number (must be first!) */
2034Srgrimes	fprintf(tfp, "V%d\n", QF_VERSION);
2044Srgrimes
2054Srgrimes	/* output creation time */
2064Srgrimes	fprintf(tfp, "T%ld\n", (long) e->e_ctime);
2074Srgrimes
2084Srgrimes	/* output last delivery time */
2094Srgrimes	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
2104Srgrimes
2114Srgrimes	/* output number of delivery attempts */
2124Srgrimes	fprintf(tfp, "N%d\n", e->e_ntries);
2134Srgrimes
2144Srgrimes	/* output message priority */
2154Srgrimes	fprintf(tfp, "P%ld\n", e->e_msgpriority);
2164Srgrimes
2174Srgrimes	/* output inode number of data file */
2184Srgrimes	/* XXX should probably include device major/minor too */
2194Srgrimes	if (e->e_dfino != -1)
2204Srgrimes	{
2214Srgrimes		if (sizeof e->e_dfino > sizeof(long))
2224Srgrimes			fprintf(tfp, "I%d/%d/%s\n",
2234Srgrimes				major(e->e_dfdev), minor(e->e_dfdev),
2244Srgrimes				quad_to_string(e->e_dfino));
2254Srgrimes		else
2264Srgrimes			fprintf(tfp, "I%d/%d/%lu\n",
2274Srgrimes				major(e->e_dfdev), minor(e->e_dfdev),
2284Srgrimes				(unsigned long) e->e_dfino);
2294Srgrimes	}
2304Srgrimes
2314Srgrimes	/* output body type */
2324Srgrimes	if (e->e_bodytype != NULL)
2334Srgrimes		fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
2344Srgrimes
2354Srgrimes#if _FFR_SAVE_CHARSET
2364Srgrimes	if (e->e_charset != NULL)
2374Srgrimes		fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
2384Srgrimes#endif
2394Srgrimes
2404Srgrimes	/* message from envelope, if it exists */
2414Srgrimes	if (e->e_message != NULL)
2424Srgrimes		fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
2434Srgrimes
2444Srgrimes	/* send various flag bits through */
2454Srgrimes	p = buf;
2464Srgrimes	if (bitset(EF_WARNING, e->e_flags))
2474Srgrimes		*p++ = 'w';
2484Srgrimes	if (bitset(EF_RESPONSE, e->e_flags))
2494Srgrimes		*p++ = 'r';
2504Srgrimes	if (bitset(EF_HAS8BIT, e->e_flags))
2514Srgrimes		*p++ = '8';
2524Srgrimes	if (bitset(EF_DELETE_BCC, e->e_flags))
2534Srgrimes		*p++ = 'b';
2544Srgrimes	if (bitset(EF_RET_PARAM, e->e_flags))
2554Srgrimes		*p++ = 'd';
2564Srgrimes	if (bitset(EF_NO_BODY_RETN, e->e_flags))
2574Srgrimes		*p++ = 'n';
2584Srgrimes	*p++ = '\0';
2594Srgrimes	if (buf[0] != '\0')
2604Srgrimes		fprintf(tfp, "F%s\n", buf);
2614Srgrimes
2624Srgrimes	/* $r and $s and $_ macro values */
2634Srgrimes	if ((p = macvalue('r', e)) != NULL)
2644Srgrimes		fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
2654Srgrimes	if ((p = macvalue('s', e)) != NULL)
2664Srgrimes		fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
2674Srgrimes	if ((p = macvalue('_', e)) != NULL)
2684Srgrimes		fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
2694Srgrimes
2704Srgrimes	/* output name of sender */
2714Srgrimes	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
2724Srgrimes		p = e->e_sender;
2734Srgrimes	else
2744Srgrimes		p = e->e_from.q_paddr;
2754Srgrimes	fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
2764Srgrimes
2774Srgrimes	/* output ESMTP-supplied "original" information */
2784Srgrimes	if (e->e_envid != NULL)
2794Srgrimes		fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
2804Srgrimes
2814Srgrimes	/* output list of recipient addresses */
2824Srgrimes	printctladdr(NULL, NULL);
2834Srgrimes	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
2844Srgrimes	{
2854Srgrimes		if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))
2864Srgrimes		{
2874Srgrimes#if XDEBUG
2884Srgrimes			if (bitset(QQUEUEUP, q->q_flags))
2894Srgrimes				sm_syslog(LOG_DEBUG, e->e_id,
2904Srgrimes					"dropenvelope: q_flags = %x, paddr = %s",
2914Srgrimes					q->q_flags, q->q_paddr);
2924Srgrimes#endif
2934Srgrimes			continue;
2944Srgrimes		}
2954Srgrimes		printctladdr(q, tfp);
2964Srgrimes		if (q->q_orcpt != NULL)
2974Srgrimes			fprintf(tfp, "Q%s\n",
2984Srgrimes				denlstring(q->q_orcpt, TRUE, FALSE));
2994Srgrimes		putc('R', tfp);
3004Srgrimes		if (bitset(QPRIMARY, q->q_flags))
3014Srgrimes			putc('P', tfp);
3024Srgrimes		if (bitset(QHASNOTIFY, q->q_flags))
3034Srgrimes			putc('N', tfp);
3044Srgrimes		if (bitset(QPINGONSUCCESS, q->q_flags))
3054Srgrimes			putc('S', tfp);
3064Srgrimes		if (bitset(QPINGONFAILURE, q->q_flags))
3074Srgrimes			putc('F', tfp);
3084Srgrimes		if (bitset(QPINGONDELAY, q->q_flags))
3094Srgrimes			putc('D', tfp);
3104Srgrimes		putc(':', tfp);
3114Srgrimes		fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
3124Srgrimes		if (announce)
3134Srgrimes		{
3144Srgrimes			e->e_to = q->q_paddr;
3154Srgrimes			message("queued");
3164Srgrimes			if (LogLevel > 8)
3174Srgrimes				logdelivery(q->q_mailer, NULL, "queued",
3184Srgrimes					    NULL, (time_t) 0, e);
3194Srgrimes			e->e_to = NULL;
3204Srgrimes		}
3214Srgrimes		if (tTd(40, 1))
3224Srgrimes		{
3234Srgrimes			printf("queueing ");
3244Srgrimes			printaddr(q, FALSE);
3254Srgrimes		}
3264Srgrimes	}
3274Srgrimes
3284Srgrimes	/*
3294Srgrimes	**  Output headers for this message.
3304Srgrimes	**	Expand macros completely here.  Queue run will deal with
3314Srgrimes	**	everything as absolute headers.
3324Srgrimes	**		All headers that must be relative to the recipient
3334Srgrimes	**		can be cracked later.
3344Srgrimes	**	We set up a "null mailer" -- i.e., a mailer that will have
3354Srgrimes	**	no effect on the addresses as they are output.
3364Srgrimes	*/
3374Srgrimes
3384Srgrimes	bzero((char *) &nullmailer, sizeof nullmailer);
3394Srgrimes	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
3404Srgrimes			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
3414Srgrimes	nullmailer.m_eol = "\n";
3424Srgrimes	bzero(&mcibuf, sizeof mcibuf);
3434Srgrimes	mcibuf.mci_mailer = &nullmailer;
3444Srgrimes	mcibuf.mci_out = tfp;
3454Srgrimes
3464Srgrimes	define('g', "\201f", e);
3474Srgrimes	for (h = e->e_header; h != NULL; h = h->h_link)
3484Srgrimes	{
3494Srgrimes		extern bool bitzerop __P((BITMAP));
3504Srgrimes
3514Srgrimes		/* don't output null headers */
3524Srgrimes		if (h->h_value == NULL || h->h_value[0] == '\0')
3534Srgrimes			continue;
3544Srgrimes
3554Srgrimes		/* don't output resent headers on non-resent messages */
3564Srgrimes		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
3574Srgrimes			continue;
3584Srgrimes
3594Srgrimes		/* expand macros; if null, don't output header at all */
3604Srgrimes		if (bitset(H_DEFAULT, h->h_flags))
3614Srgrimes		{
3624Srgrimes			(void) expand(h->h_value, buf, sizeof buf, e);
3634Srgrimes			if (buf[0] == '\0')
3644Srgrimes				continue;
3654Srgrimes		}
3664Srgrimes
3674Srgrimes		/* output this header */
3684Srgrimes		fprintf(tfp, "H");
3694Srgrimes
3704Srgrimes		/* if conditional, output the set of conditions */
3714Srgrimes		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
3724Srgrimes		{
3734Srgrimes			int j;
3744Srgrimes
3754Srgrimes			(void) putc('?', tfp);
3764Srgrimes			for (j = '\0'; j <= '\177'; j++)
3774Srgrimes				if (bitnset(j, h->h_mflags))
3784Srgrimes					(void) putc(j, tfp);
3794Srgrimes			(void) putc('?', tfp);
3804Srgrimes		}
3814Srgrimes
3824Srgrimes		/* output the header: expand macros, convert addresses */
3834Srgrimes		if (bitset(H_DEFAULT, h->h_flags))
3844Srgrimes		{
3854Srgrimes			fprintf(tfp, "%s: %s\n",
3864Srgrimes				h->h_field,
3874Srgrimes				denlstring(buf, FALSE, TRUE));
3884Srgrimes		}
3894Srgrimes		else if (bitset(H_FROM|H_RCPT, h->h_flags))
3904Srgrimes		{
3914Srgrimes			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
3924Srgrimes			FILE *savetrace = TrafficLogFile;
3933723Sbde
3943723Sbde			TrafficLogFile = NULL;
3953723Sbde
3963723Sbde			if (bitset(H_FROM, h->h_flags))
3973723Sbde				oldstyle = FALSE;
3984Srgrimes
3994Srgrimes			commaize(h, h->h_value, oldstyle, &mcibuf, e);
4004Srgrimes
4014Srgrimes			TrafficLogFile = savetrace;
4024Srgrimes		}
4034Srgrimes		else
4044Srgrimes		{
4054Srgrimes			fprintf(tfp, "%s: %s\n",
4064Srgrimes				h->h_field,
4074Srgrimes				denlstring(h->h_value, FALSE, TRUE));
4084Srgrimes		}
4094Srgrimes	}
4104Srgrimes
4114Srgrimes	/*
4124Srgrimes	**  Clean up.
4134Srgrimes	**
4144Srgrimes	**	Write a terminator record -- this is to prevent
4154Srgrimes	**	scurrilous crackers from appending any data.
4164Srgrimes	*/
4174Srgrimes
4184Srgrimes	fprintf(tfp, ".\n");
4194Srgrimes
4204Srgrimes	if (fflush(tfp) < 0 ||
4214Srgrimes	    (SuperSafe && fsync(fileno(tfp)) < 0) ||
4224Srgrimes	    ferror(tfp))
4234Srgrimes	{
4244Srgrimes		if (newid)
4254Srgrimes			syserr("!552 Error writing control file %s", tf);
4264Srgrimes		else
4274Srgrimes			syserr("!452 Error writing control file %s", tf);
4284Srgrimes	}
4294Srgrimes
4304Srgrimes	if (!newid)
4314Srgrimes	{
4323723Sbde		/* rename (locked) tf to be (locked) qf */
4333723Sbde		qf = queuename(e, 'q');
4343723Sbde		if (rename(tf, qf) < 0)
4353723Sbde			syserr("cannot rename(%s, %s), uid=%d",
4363723Sbde				tf, qf, geteuid());
4374Srgrimes
4384Srgrimes		/* close and unlock old (locked) qf */
4394Srgrimes		if (e->e_lockfp != NULL)
4404Srgrimes			(void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
4414Srgrimes		e->e_lockfp = tfp;
4424Srgrimes	}
4434Srgrimes	else
4444Srgrimes		qf = tf;
4454Srgrimes	errno = 0;
4464Srgrimes	e->e_flags |= EF_INQUEUE;
4474Srgrimes
4484Srgrimes	/* save log info */
4494Srgrimes	if (LogLevel > 79)
4504Srgrimes		sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
4514Srgrimes
4524Srgrimes	if (tTd(40, 1))
4534Srgrimes		printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
4544Srgrimes	return;
4554Srgrimes}
4564Srgrimes
4574Srgrimesvoid
4584Srgrimesprintctladdr(a, tfp)
4594Srgrimes	register ADDRESS *a;
4602810Sbde	FILE *tfp;
4612810Sbde{
4624Srgrimes	char *uname;
4634Srgrimes	register ADDRESS *q;
4643723Sbde	uid_t uid;
4654Srgrimes	gid_t gid;
4664Srgrimes	static ADDRESS *lastctladdr = NULL;
4674Srgrimes	static uid_t lastuid;
4684Srgrimes
4694Srgrimes	/* initialization */
4704Srgrimes	if (a == NULL || a->q_alias == NULL || tfp == NULL)
4714Srgrimes	{
4724Srgrimes		if (lastctladdr != NULL && tfp != NULL)
4734Srgrimes			fprintf(tfp, "C\n");
4744Srgrimes		lastctladdr = NULL;
4754Srgrimes		lastuid = 0;
4764Srgrimes		return;
4774Srgrimes	}
4784Srgrimes
4794Srgrimes	/* find the active uid */
4804Srgrimes	q = getctladdr(a);
4814Srgrimes	if (q == NULL)
4824Srgrimes	{
4834Srgrimes		uname = NULL;
4844Srgrimes		uid = 0;
4854Srgrimes		gid = 0;
4864Srgrimes	}
4874Srgrimes	else
4884Srgrimes	{
4894Srgrimes		uname = q->q_ruser != NULL ? q->q_ruser : q->q_user;
4904Srgrimes		uid = q->q_uid;
4914Srgrimes		gid = q->q_gid;
4924Srgrimes	}
4932810Sbde	a = a->q_alias;
4942810Sbde
4952810Sbde	/* check to see if this is the same as last time */
4962810Sbde	if (lastctladdr != NULL && uid == lastuid &&
4972810Sbde	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
4982810Sbde		return;
4992810Sbde	lastuid = uid;
5002810Sbde	lastctladdr = a;
5012810Sbde
5024Srgrimes	if (uid == 0 || uname == NULL || uname[0] == '\0')
5034Srgrimes		fprintf(tfp, "C");
5044Srgrimes	else
5054Srgrimes		fprintf(tfp, "C%s:%ld:%ld",
5064Srgrimes			denlstring(uname, TRUE, FALSE), (long) uid, (long) gid);
5074Srgrimes	fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
5084Srgrimes}
5094Srgrimes/*
5104Srgrimes**  RUNQUEUE -- run the jobs in the queue.
5114Srgrimes**
5124Srgrimes**	Gets the stuff out of the queue in some presumably logical
5134Srgrimes**	order and processes them.
5144Srgrimes**
5154Srgrimes**	Parameters:
5164Srgrimes**		forkflag -- TRUE if the queue scanning should be done in
5174Srgrimes**			a child process.  We double-fork so it is not our
5184Srgrimes**			child and we don't have to clean up after it.
5194Srgrimes**		verbose -- if TRUE, print out status information.
5204Srgrimes**
5214Srgrimes**	Returns:
5224Srgrimes**		TRUE if the queue run successfully began.
5234Srgrimes**
5244Srgrimes**	Side Effects:
5254Srgrimes**		runs things in the mail queue.
5264Srgrimes*/
5274Srgrimes
5284SrgrimesENVELOPE	QueueEnvelope;		/* the queue run envelope */
5294Srgrimesextern int	get_num_procs_online __P((void));
5304Srgrimes
5314Srgrimesbool
5324Srgrimesrunqueue(forkflag, verbose)
5334Srgrimes	bool forkflag;
5344Srgrimes	bool verbose;
5354Srgrimes{
5364Srgrimes	register ENVELOPE *e;
5374Srgrimes	int njobs;
5384Srgrimes	int sequenceno = 0;
5394Srgrimes	time_t current_la_time;
5404Srgrimes	extern ENVELOPE BlankEnvelope;
5414Srgrimes	extern void clrdaemon __P((void));
5424Srgrimes	extern void runqueueevent __P((void));
5434Srgrimes
5444Srgrimes	DoQueueRun = FALSE;
5454Srgrimes
5464Srgrimes	/*
5474Srgrimes	**  If no work will ever be selected, don't even bother reading
5484Srgrimes	**  the queue.
5494Srgrimes	*/
5504Srgrimes
5514Srgrimes	CurrentLA = getla();	/* get load average */
5524Srgrimes	current_la_time = curtime();
5534Srgrimes
5544Srgrimes	if (shouldqueue(WkRecipFact, current_la_time))
5554Srgrimes	{
5564Srgrimes		char *msg = "Skipping queue run -- load average too high";
5574Srgrimes
5584Srgrimes		if (verbose)
5594Srgrimes			message("458 %s\n", msg);
5604Srgrimes		if (LogLevel > 8)
5614Srgrimes			sm_syslog(LOG_INFO, NOQID,
5624Srgrimes				"runqueue: %s",
5634Srgrimes				msg);
5644Srgrimes		if (forkflag && QueueIntvl != 0)
5654Srgrimes			(void) setevent(QueueIntvl, runqueueevent, 0);
5664Srgrimes		return FALSE;
5674Srgrimes	}
5684Srgrimes
5694Srgrimes	/*
5704Srgrimes	**  See if we already have too many children.
5714Srgrimes	*/
5724Srgrimes
5734Srgrimes	if (forkflag && QueueIntvl != 0 &&
5744Srgrimes	    MaxChildren > 0 && CurChildren >= MaxChildren)
5754Srgrimes	{
5764Srgrimes		(void) setevent(QueueIntvl, runqueueevent, 0);
5774Srgrimes		return FALSE;
5784Srgrimes	}
5794Srgrimes
5804Srgrimes	/*
5814Srgrimes	**  See if we want to go off and do other useful work.
5824Srgrimes	*/
5834Srgrimes
5844Srgrimes	if (forkflag)
5854Srgrimes	{
5864Srgrimes		pid_t pid;
5874Srgrimes		extern SIGFUNC_DECL intsig __P((int));
5884Srgrimes		extern SIGFUNC_DECL reapchild __P((int));
5894Srgrimes
5904Srgrimes		blocksignal(SIGCHLD);
5914Srgrimes		(void) setsignal(SIGCHLD, reapchild);
5924Srgrimes
5934Srgrimes		pid = dofork();
5944Srgrimes		if (pid == -1)
5954Srgrimes		{
5964Srgrimes			const char *msg = "Skipping queue run -- fork() failed";
5974Srgrimes			const char *err = errstring(errno);
5984Srgrimes
5994Srgrimes			if (verbose)
6004Srgrimes				message("458 %s: %s\n", msg, err);
6014Srgrimes			if (LogLevel > 8)
6024Srgrimes				sm_syslog(LOG_INFO, NOQID,
6034Srgrimes					"runqueue: %s: %s",
6044Srgrimes					msg, err);
6054Srgrimes			if (QueueIntvl != 0)
6064Srgrimes				(void) setevent(QueueIntvl, runqueueevent, 0);
6074Srgrimes			(void) releasesignal(SIGCHLD);
6084Srgrimes			return FALSE;
6094Srgrimes		}
6104Srgrimes		if (pid != 0)
6114Srgrimes		{
6124Srgrimes			/* parent -- pick up intermediate zombie */
6134Srgrimes			(void) blocksignal(SIGALRM);
6144Srgrimes			proc_list_add(pid, "Queue runner");
6154Srgrimes			(void) releasesignal(SIGALRM);
6164Srgrimes			releasesignal(SIGCHLD);
6174Srgrimes			if (QueueIntvl != 0)
6184Srgrimes				(void) setevent(QueueIntvl, runqueueevent, 0);
6194Srgrimes			return TRUE;
6204Srgrimes		}
6214Srgrimes		/* child -- double fork and clean up signals */
6224Srgrimes		clrcontrol();
6234Srgrimes		proc_list_clear();
6244Srgrimes
6254Srgrimes		/* Add parent process as first child item */
6264Srgrimes		proc_list_add(getpid(), "Queue runner child process");
6274Srgrimes		releasesignal(SIGCHLD);
6284Srgrimes		(void) setsignal(SIGCHLD, SIG_DFL);
6294Srgrimes		(void) setsignal(SIGHUP, intsig);
6304Srgrimes	}
6314Srgrimes
6324Srgrimes	sm_setproctitle(TRUE, "running queue: %s", QueueDir);
6334Srgrimes
6344Srgrimes	if (LogLevel > 69)
6354Srgrimes		sm_syslog(LOG_DEBUG, NOQID,
6364Srgrimes			"runqueue %s, pid=%d, forkflag=%d",
6374Srgrimes			QueueDir, getpid(), forkflag);
6384Srgrimes
6394Srgrimes	/*
6404Srgrimes	**  Release any resources used by the daemon code.
6414Srgrimes	*/
6424Srgrimes
6434Srgrimes# if DAEMON
6444Srgrimes	clrdaemon();
6454Srgrimes# endif /* DAEMON */
6464Srgrimes
6474Srgrimes	/* force it to run expensive jobs */
6484Srgrimes	NoConnect = FALSE;
6494Srgrimes
6504Srgrimes	/* drop privileges */
6514Srgrimes	if (geteuid() == (uid_t) 0)
6524Srgrimes		(void) drop_privileges(FALSE);
6534Srgrimes
6544Srgrimes	/*
6554Srgrimes	**  Create ourselves an envelope
6564Srgrimes	*/
6574Srgrimes
6584Srgrimes	CurEnv = &QueueEnvelope;
6594Srgrimes	e = newenvelope(&QueueEnvelope, CurEnv);
6604Srgrimes	e->e_flags = BlankEnvelope.e_flags;
6614Srgrimes
6624Srgrimes	/* make sure we have disconnected from parent */
6634Srgrimes	if (forkflag)
6644Srgrimes	{
6654Srgrimes		disconnect(1, e);
6664Srgrimes		QuickAbort = FALSE;
6674Srgrimes	}
6684Srgrimes
6694Srgrimes	/*
6704Srgrimes	**  Make sure the alias database is open.
6714Srgrimes	*/
6724Srgrimes
6734Srgrimes	initmaps(FALSE, e);
6744Srgrimes
6754Srgrimes	/*
6764Srgrimes	**  If we are running part of the queue, always ignore stored
6774Srgrimes	**  host status.
6784Srgrimes	*/
6794Srgrimes
6804Srgrimes	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
6814Srgrimes	    QueueLimitRecipient != NULL)
6824Srgrimes	{
6834Srgrimes		IgnoreHostStatus = TRUE;
6844Srgrimes		MinQueueAge = 0;
6854Srgrimes	}
6864Srgrimes
6874Srgrimes	/*
6884Srgrimes	**  Start making passes through the queue.
6894Srgrimes	**	First, read and sort the entire queue.
6904Srgrimes	**	Then, process the work in that order.
6914Srgrimes	**		But if you take too long, start over.
6924Srgrimes	*/
6934Srgrimes
6944Srgrimes	/* order the existing work requests */
6954Srgrimes	njobs = orderq(FALSE);
6964Srgrimes
6974Srgrimes	/* process them once at a time */
6984Srgrimes	while (WorkQ != NULL)
699	{
700		WORK *w = WorkQ;
701
702		WorkQ = WorkQ->w_next;
703		e->e_to = NULL;
704
705		/*
706		**  Ignore jobs that are too expensive for the moment.
707		**
708		**	Get new load average every 30 seconds.
709		*/
710
711		if (current_la_time < curtime() - 30)
712		{
713			CurrentLA = getla();
714			current_la_time = curtime();
715		}
716		if (shouldqueue(WkRecipFact, current_la_time))
717		{
718			char *msg = "Aborting queue run: load average too high";
719
720			if (Verbose)
721				message("%s", msg);
722			if (LogLevel > 8)
723				sm_syslog(LOG_INFO, NOQID,
724					"runqueue: %s",
725					msg);
726			break;
727		}
728		sequenceno++;
729		if (shouldqueue(w->w_pri, w->w_ctime))
730		{
731			if (Verbose)
732				message("");
733			if (QueueSortOrder == QS_BYPRIORITY)
734			{
735				if (Verbose)
736					message("Skipping %s (sequence %d of %d) and flushing rest of queue",
737						w->w_name + 2,
738						sequenceno,
739						njobs);
740				if (LogLevel > 8)
741					sm_syslog(LOG_INFO, NOQID,
742						"runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)",
743						w->w_name + 2,
744						w->w_pri,
745						CurrentLA,
746						sequenceno,
747						njobs);
748				break;
749			}
750			else if (Verbose)
751				message("Skipping %s (sequence %d of %d)",
752					w->w_name + 2, sequenceno, njobs);
753		}
754		else
755		{
756			pid_t pid;
757
758			if (Verbose)
759			{
760				message("");
761				message("Running %s (sequence %d of %d)",
762					w->w_name + 2, sequenceno, njobs);
763			}
764			pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
765			errno = 0;
766			if (pid != 0)
767				(void) waitfor(pid);
768		}
769		free(w->w_name);
770		if (w->w_host)
771			free(w->w_host);
772		free((char *) w);
773	}
774
775	/* exit without the usual cleanup */
776	e->e_id = NULL;
777	finis(TRUE, ExitStat);
778	/*NOTREACHED*/
779	return TRUE;
780}
781
782
783/*
784**  RUNQUEUEEVENT -- stub for use in setevent
785*/
786
787void
788runqueueevent()
789{
790	DoQueueRun = TRUE;
791}
792/*
793**  ORDERQ -- order the work queue.
794**
795**	Parameters:
796**		doall -- if set, include everything in the queue (even
797**			the jobs that cannot be run because the load
798**			average is too high).  Otherwise, exclude those
799**			jobs.
800**
801**	Returns:
802**		The number of request in the queue (not necessarily
803**		the number of requests in WorkQ however).
804**
805**	Side Effects:
806**		Sets WorkQ to the queue of available work, in order.
807*/
808
809# define NEED_P		001
810# define NEED_T		002
811# define NEED_R		004
812# define NEED_S		010
813
814static WORK	*WorkList = NULL;
815static int	WorkListSize = 0;
816
817int
818orderq(doall)
819	bool doall;
820{
821	register struct dirent *d;
822	register WORK *w;
823	register char *p;
824	DIR *f;
825	register int i;
826	int wn = -1;
827	int wc;
828	QUEUE_CHAR *check;
829
830	if (tTd(41, 1))
831	{
832		printf("orderq:\n");
833
834		check = QueueLimitId;
835		while (check != NULL)
836		{
837			printf("\tQueueLimitId = %s\n",
838			       check->queue_match);
839			check = check->queue_next;
840		}
841
842		check = QueueLimitSender;
843		while (check != NULL)
844		{
845			printf("\tQueueLimitSender = %s\n",
846			       check->queue_match);
847			check = check->queue_next;
848		}
849
850		check = QueueLimitRecipient;
851		while (check != NULL)
852		{
853			printf("\tQueueLimitRecipient = %s\n",
854			       check->queue_match);
855			check = check->queue_next;
856		}
857	}
858
859	/* clear out old WorkQ */
860	for (w = WorkQ; w != NULL; )
861	{
862		register WORK *nw = w->w_next;
863
864		WorkQ = nw;
865		free(w->w_name);
866		if (w->w_host)
867			free(w->w_host);
868		free((char *) w);
869		w = nw;
870	}
871
872	/* open the queue directory */
873	f = opendir(".");
874	if (f == NULL)
875	{
876		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
877		return (0);
878	}
879
880	/*
881	**  Read the work directory.
882	*/
883
884	while ((d = readdir(f)) != NULL)
885	{
886		FILE *cf;
887		int qfver = 0;
888		char lbuf[MAXNAME + 1];
889		extern bool strcontainedin __P((char *, char *));
890
891		if (tTd(41, 50))
892			printf("orderq: checking %s\n", d->d_name);
893
894		/* is this an interesting entry? */
895		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
896			continue;
897
898		if (strlen(d->d_name) > MAXQFNAME)
899		{
900			if (Verbose)
901				printf("orderq: %s too long, %d max characters\n",
902					d->d_name, MAXQFNAME);
903			if (LogLevel > 0)
904				sm_syslog(LOG_ALERT, NOQID,
905					"orderq: %s too long, %d max characters",
906					d->d_name, MAXQFNAME);
907			continue;
908		}
909
910		check = QueueLimitId;
911		while (check != NULL)
912		{
913			if (strcontainedin(check->queue_match, d->d_name))
914				break;
915			else
916				check = check->queue_next;
917		}
918		if (QueueLimitId != NULL && check == NULL)
919			continue;
920
921#ifdef PICKY_QF_NAME_CHECK
922		/*
923		**  Check queue name for plausibility.  This handles
924		**  both old and new type ids.
925		*/
926
927		p = d->d_name + 2;
928		if (isupper(p[0]) && isupper(p[2]))
929			p += 3;
930		else if (isupper(p[1]))
931			p += 2;
932		else
933			p = d->d_name;
934		for (i = 0; isdigit(*p); p++)
935			i++;
936		if (i < 5 || *p != '\0')
937		{
938			if (Verbose)
939				printf("orderq: bogus qf name %s\n", d->d_name);
940			if (LogLevel > 0)
941				sm_syslog(LOG_ALERT, NOQID,
942					"orderq: bogus qf name %s",
943					d->d_name);
944			if (strlen(d->d_name) > (SIZE_T) MAXNAME)
945				d->d_name[MAXNAME] = '\0';
946			strcpy(lbuf, d->d_name);
947			lbuf[0] = 'Q';
948			(void) rename(d->d_name, lbuf);
949			continue;
950		}
951#endif
952
953		/* open control file (if not too many files) */
954		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
955		{
956			if (wn == MaxQueueRun && LogLevel > 0)
957				sm_syslog(LOG_ALERT, NOQID,
958					"WorkList for %s maxed out at %d",
959					QueueDir, MaxQueueRun);
960			continue;
961		}
962		if (wn >= WorkListSize)
963		{
964			extern void grow_wlist __P((void));
965
966			grow_wlist();
967			if (wn >= WorkListSize)
968				continue;
969		}
970
971		cf = fopen(d->d_name, "r");
972		if (cf == NULL)
973		{
974			/* this may be some random person sending hir msgs */
975			/* syserr("orderq: cannot open %s", cbuf); */
976			if (tTd(41, 2))
977				printf("orderq: cannot open %s: %s\n",
978					d->d_name, errstring(errno));
979			errno = 0;
980			wn--;
981			continue;
982		}
983		w = &WorkList[wn];
984		w->w_name = newstr(d->d_name);
985		w->w_host = NULL;
986		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
987		w->w_tooyoung = FALSE;
988
989		/* make sure jobs in creation don't clog queue */
990		w->w_pri = 0x7fffffff;
991		w->w_ctime = 0;
992
993		/* extract useful information */
994		i = NEED_P | NEED_T;
995		if (QueueLimitSender != NULL)
996			i |= NEED_S;
997		if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
998			i |= NEED_R;
999		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
1000		{
1001			int c;
1002			time_t age;
1003			extern bool strcontainedin __P((char *, char *));
1004
1005			p = strchr(lbuf, '\n');
1006			if (p != NULL)
1007				*p = '\0';
1008			else
1009			{
1010				/* flush rest of overly long line */
1011				while ((c = getc(cf)) != EOF && c != '\n')
1012					continue;
1013			}
1014
1015			switch (lbuf[0])
1016			{
1017			  case 'V':
1018				qfver = atoi(&lbuf[1]);
1019				break;
1020
1021			  case 'P':
1022				w->w_pri = atol(&lbuf[1]);
1023				i &= ~NEED_P;
1024				break;
1025
1026			  case 'T':
1027				w->w_ctime = atol(&lbuf[1]);
1028				i &= ~NEED_T;
1029				break;
1030
1031			  case 'R':
1032				if (w->w_host == NULL &&
1033				    (p = strrchr(&lbuf[1], '@')) != NULL)
1034					w->w_host = newstr(&p[1]);
1035				if (QueueLimitRecipient == NULL)
1036				{
1037					i &= ~NEED_R;
1038					break;
1039				}
1040				if (qfver > 0)
1041				{
1042					p = strchr(&lbuf[1], ':');
1043					if (p == NULL)
1044						p = &lbuf[1];
1045				}
1046				else
1047					p = &lbuf[1];
1048				check = QueueLimitRecipient;
1049				while (check != NULL)
1050				{
1051					if (strcontainedin(check->queue_match,
1052							   p))
1053						break;
1054					else
1055						check = check->queue_next;
1056				}
1057				if (check != NULL)
1058					i &= ~NEED_R;
1059				break;
1060
1061			  case 'S':
1062				  check = QueueLimitSender;
1063				  while (check != NULL)
1064				  {
1065					  if (strcontainedin(check->queue_match,
1066							     &lbuf[1]))
1067						  break;
1068					  else
1069						  check = check->queue_next;
1070				  }
1071				  if (check != NULL)
1072					  i &= ~NEED_S;
1073				break;
1074
1075			  case 'K':
1076				age = curtime() - (time_t) atol(&lbuf[1]);
1077				if (age >= 0 && MinQueueAge > 0 &&
1078				    age < MinQueueAge)
1079					w->w_tooyoung = TRUE;
1080				break;
1081
1082			  case 'N':
1083				if (atol(&lbuf[1]) == 0)
1084					w->w_tooyoung = FALSE;
1085				break;
1086			}
1087		}
1088		(void) fclose(cf);
1089
1090		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
1091		    bitset(NEED_R|NEED_S, i))
1092		{
1093			/* don't even bother sorting this job in */
1094			if (tTd(41, 49))
1095				printf("skipping %s (%x)\n", w->w_name, i);
1096			free(w->w_name);
1097			if (w->w_host)
1098				free(w->w_host);
1099			wn--;
1100		}
1101	}
1102	(void) closedir(f);
1103	wn++;
1104
1105	wc = min(wn, WorkListSize);
1106	if (wc > MaxQueueRun && MaxQueueRun > 0)
1107		wc = MaxQueueRun;
1108
1109	if (QueueSortOrder == QS_BYHOST)
1110	{
1111		extern int workcmpf1();
1112		extern int workcmpf2();
1113
1114		/*
1115		**  Sort the work directory for the first time,
1116		**  based on host name, lock status, and priority.
1117		*/
1118
1119		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
1120
1121		/*
1122		**  If one message to host is locked, "lock" all messages
1123		**  to that host.
1124		*/
1125
1126		i = 0;
1127		while (i < wc)
1128		{
1129			if (!WorkList[i].w_lock)
1130			{
1131				i++;
1132				continue;
1133			}
1134			w = &WorkList[i];
1135			while (++i < wc)
1136			{
1137				extern int sm_strcasecmp __P((char *, char *));
1138
1139				if (WorkList[i].w_host == NULL &&
1140				    w->w_host == NULL)
1141					WorkList[i].w_lock = TRUE;
1142				else if (WorkList[i].w_host != NULL &&
1143					 w->w_host != NULL &&
1144					 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
1145					WorkList[i].w_lock = TRUE;
1146				else
1147					break;
1148			}
1149		}
1150
1151		/*
1152		**  Sort the work directory for the second time,
1153		**  based on lock status, host name, and priority.
1154		*/
1155
1156		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
1157	}
1158	else if (QueueSortOrder == QS_BYTIME)
1159	{
1160		extern int workcmpf3();
1161
1162		/*
1163		**  Simple sort based on submission time only.
1164		*/
1165
1166		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
1167	}
1168	else
1169	{
1170		extern int workcmpf0();
1171
1172		/*
1173		**  Simple sort based on queue priority only.
1174		*/
1175
1176		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
1177	}
1178
1179	/*
1180	**  Convert the work list into canonical form.
1181	**	Should be turning it into a list of envelopes here perhaps.
1182	*/
1183
1184	WorkQ = NULL;
1185	for (i = wc; --i >= 0; )
1186	{
1187		w = (WORK *) xalloc(sizeof *w);
1188		w->w_name = WorkList[i].w_name;
1189		w->w_host = WorkList[i].w_host;
1190		w->w_lock = WorkList[i].w_lock;
1191		w->w_tooyoung = WorkList[i].w_tooyoung;
1192		w->w_pri = WorkList[i].w_pri;
1193		w->w_ctime = WorkList[i].w_ctime;
1194		w->w_next = WorkQ;
1195		WorkQ = w;
1196	}
1197	if (WorkList != NULL)
1198		free(WorkList);
1199	WorkList = NULL;
1200	WorkListSize = 0;
1201
1202	if (tTd(40, 1))
1203	{
1204		for (w = WorkQ; w != NULL; w = w->w_next)
1205			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
1206	}
1207
1208	return (wn);
1209}
1210/*
1211**  GROW_WLIST -- make the work list larger
1212**
1213**	Parameters:
1214**		none.
1215**
1216**	Returns:
1217**		none.
1218**
1219**	Side Effects:
1220**		Adds another QUEUESEGSIZE entries to WorkList if possible.
1221**		It can fail if there isn't enough memory, so WorkListSize
1222**		should be checked again upon return.
1223*/
1224
1225void
1226grow_wlist()
1227{
1228	if (tTd(41, 1))
1229		printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
1230	if (WorkList == NULL)
1231	{
1232		WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
1233		WorkListSize = QUEUESEGSIZE;
1234	}
1235	else
1236	{
1237		int newsize = WorkListSize + QUEUESEGSIZE;
1238		WORK *newlist = (WORK *) realloc((char *)WorkList,
1239					  (unsigned)sizeof(WORK) * (newsize + 1));
1240
1241		if (newlist != NULL)
1242		{
1243			WorkListSize = newsize;
1244			WorkList = newlist;
1245			if (LogLevel > 1)
1246			{
1247				sm_syslog(LOG_NOTICE, NOQID,
1248					"grew WorkList for %s to %d",
1249					QueueDir, WorkListSize);
1250			}
1251		}
1252		else if (LogLevel > 0)
1253		{
1254			sm_syslog(LOG_ALERT, NOQID,
1255				"FAILED to grow WorkList for %s to %d",
1256				QueueDir, newsize);
1257		}
1258	}
1259	if (tTd(41, 1))
1260		printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
1261}
1262/*
1263**  WORKCMPF0 -- simple priority-only compare function.
1264**
1265**	Parameters:
1266**		a -- the first argument.
1267**		b -- the second argument.
1268**
1269**	Returns:
1270**		-1 if a < b
1271**		 0 if a == b
1272**		+1 if a > b
1273**
1274**	Side Effects:
1275**		none.
1276*/
1277
1278int
1279workcmpf0(a, b)
1280	register WORK *a;
1281	register WORK *b;
1282{
1283	long pa = a->w_pri;
1284	long pb = b->w_pri;
1285
1286	if (pa == pb)
1287		return 0;
1288	else if (pa > pb)
1289		return 1;
1290	else
1291		return -1;
1292}
1293/*
1294**  WORKCMPF1 -- first compare function for ordering work based on host name.
1295**
1296**	Sorts on host name, lock status, and priority in that order.
1297**
1298**	Parameters:
1299**		a -- the first argument.
1300**		b -- the second argument.
1301**
1302**	Returns:
1303**		<0 if a < b
1304**		 0 if a == b
1305**		>0 if a > b
1306**
1307**	Side Effects:
1308**		none.
1309*/
1310
1311int
1312workcmpf1(a, b)
1313	register WORK *a;
1314	register WORK *b;
1315{
1316	int i;
1317	extern int sm_strcasecmp __P((char *, char *));
1318
1319	/* host name */
1320	if (a->w_host != NULL && b->w_host == NULL)
1321		return 1;
1322	else if (a->w_host == NULL && b->w_host != NULL)
1323		return -1;
1324	if (a->w_host != NULL && b->w_host != NULL &&
1325	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1326		return i;
1327
1328	/* lock status */
1329	if (a->w_lock != b->w_lock)
1330		return b->w_lock - a->w_lock;
1331
1332	/* job priority */
1333	return a->w_pri - b->w_pri;
1334}
1335/*
1336**  WORKCMPF2 -- second compare function for ordering work based on host name.
1337**
1338**	Sorts on lock status, host name, and priority in that order.
1339**
1340**	Parameters:
1341**		a -- the first argument.
1342**		b -- the second argument.
1343**
1344**	Returns:
1345**		<0 if a < b
1346**		 0 if a == b
1347**		>0 if a > b
1348**
1349**	Side Effects:
1350**		none.
1351*/
1352
1353int
1354workcmpf2(a, b)
1355	register WORK *a;
1356	register WORK *b;
1357{
1358	int i;
1359	extern int sm_strcasecmp __P((char *, char *));
1360
1361	/* lock status */
1362	if (a->w_lock != b->w_lock)
1363		return a->w_lock - b->w_lock;
1364
1365	/* host name */
1366	if (a->w_host != NULL && b->w_host == NULL)
1367		return 1;
1368	else if (a->w_host == NULL && b->w_host != NULL)
1369		return -1;
1370	if (a->w_host != NULL && b->w_host != NULL &&
1371	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1372		return i;
1373
1374	/* job priority */
1375	return a->w_pri - b->w_pri;
1376}
1377/*
1378**  WORKCMPF3 -- simple submission-time-only compare function.
1379**
1380**	Parameters:
1381**		a -- the first argument.
1382**		b -- the second argument.
1383**
1384**	Returns:
1385**		-1 if a < b
1386**		 0 if a == b
1387**		+1 if a > b
1388**
1389**	Side Effects:
1390**		none.
1391*/
1392
1393int
1394workcmpf3(a, b)
1395	register WORK *a;
1396	register WORK *b;
1397{
1398	if (a->w_ctime > b->w_ctime)
1399		return 1;
1400	else if (a->w_ctime < b->w_ctime)
1401		return -1;
1402	else
1403		return 0;
1404}
1405/*
1406**  DOWORK -- do a work request.
1407**
1408**	Parameters:
1409**		id -- the ID of the job to run.
1410**		forkflag -- if set, run this in background.
1411**		requeueflag -- if set, reinstantiate the queue quickly.
1412**			This is used when expanding aliases in the queue.
1413**			If forkflag is also set, it doesn't wait for the
1414**			child.
1415**		e - the envelope in which to run it.
1416**
1417**	Returns:
1418**		process id of process that is running the queue job.
1419**
1420**	Side Effects:
1421**		The work request is satisfied if possible.
1422*/
1423
1424pid_t
1425dowork(id, forkflag, requeueflag, e)
1426	char *id;
1427	bool forkflag;
1428	bool requeueflag;
1429	register ENVELOPE *e;
1430{
1431	register pid_t pid;
1432	extern bool readqf __P((ENVELOPE *));
1433
1434	if (tTd(40, 1))
1435		printf("dowork(%s)\n", id);
1436
1437	/*
1438	**  Fork for work.
1439	*/
1440
1441	if (forkflag)
1442	{
1443		pid = fork();
1444		if (pid < 0)
1445		{
1446			syserr("dowork: cannot fork");
1447			return 0;
1448		}
1449		else if (pid > 0)
1450		{
1451			/* parent -- clean out connection cache */
1452			mci_flush(FALSE, NULL);
1453		}
1454		else
1455		{
1456			/* child -- error messages to the transcript */
1457			QuickAbort = OnlyOneError = FALSE;
1458
1459			/*
1460			**  Since the delivery may happen in a child and the
1461			**  parent does not wait, the parent may close the
1462			**  maps thereby removing any shared memory used by
1463			**  the map.  Therefore, open a copy of the maps for
1464			**  the delivery process.
1465			*/
1466
1467			initmaps(FALSE, e);
1468		}
1469	}
1470	else
1471	{
1472		pid = 0;
1473	}
1474
1475	if (pid == 0)
1476	{
1477		/*
1478		**  CHILD
1479		**	Lock the control file to avoid duplicate deliveries.
1480		**		Then run the file as though we had just read it.
1481		**	We save an idea of the temporary name so we
1482		**		can recover on interrupt.
1483		*/
1484
1485		/* set basic modes, etc. */
1486		(void) alarm(0);
1487		clearenvelope(e, FALSE);
1488		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1489		e->e_sendmode = SM_DELIVER;
1490		e->e_errormode = EM_MAIL;
1491		e->e_id = id;
1492		GrabTo = UseErrorsTo = FALSE;
1493		ExitStat = EX_OK;
1494		if (forkflag)
1495		{
1496			disconnect(1, e);
1497			OpMode = MD_DELIVER;
1498		}
1499		sm_setproctitle(TRUE, "%s: from queue", id);
1500		if (LogLevel > 76)
1501			sm_syslog(LOG_DEBUG, e->e_id,
1502				"dowork, pid=%d",
1503				getpid());
1504
1505		/* don't use the headers from sendmail.cf... */
1506		e->e_header = NULL;
1507
1508		/* read the queue control file -- return if locked */
1509		if (!readqf(e))
1510		{
1511			if (tTd(40, 4) && e->e_id != NULL)
1512				printf("readqf(%s) failed\n", e->e_id);
1513			e->e_id = NULL;
1514			if (forkflag)
1515				finis(FALSE, EX_OK);
1516			else
1517				return 0;
1518		}
1519
1520		e->e_flags |= EF_INQUEUE;
1521		eatheader(e, requeueflag);
1522
1523		if (requeueflag)
1524			queueup(e, FALSE);
1525
1526		/* do the delivery */
1527		sendall(e, SM_DELIVER);
1528
1529		/* finish up and exit */
1530		if (forkflag)
1531			finis(TRUE, ExitStat);
1532		else
1533			dropenvelope(e, TRUE);
1534	}
1535	e->e_id = NULL;
1536	return pid;
1537}
1538/*
1539**  READQF -- read queue file and set up environment.
1540**
1541**	Parameters:
1542**		e -- the envelope of the job to run.
1543**
1544**	Returns:
1545**		TRUE if it successfully read the queue file.
1546**		FALSE otherwise.
1547**
1548**	Side Effects:
1549**		The queue file is returned locked.
1550*/
1551
1552bool
1553readqf(e)
1554	register ENVELOPE *e;
1555{
1556	register FILE *qfp;
1557	ADDRESS *ctladdr;
1558	struct stat st;
1559	char *bp;
1560	int qfver = 0;
1561	long hdrsize = 0;
1562	register char *p;
1563	char *orcpt = NULL;
1564	bool nomore = FALSE;
1565	char qf[MAXQFNAME];
1566	char buf[MAXLINE];
1567	extern ADDRESS *setctluser __P((char *, int));
1568
1569	/*
1570	**  Read and process the file.
1571	*/
1572
1573	strcpy(qf, queuename(e, 'q'));
1574	qfp = fopen(qf, "r+");
1575	if (qfp == NULL)
1576	{
1577		if (tTd(40, 8))
1578			printf("readqf(%s): fopen failure (%s)\n",
1579				qf, errstring(errno));
1580		if (errno != ENOENT)
1581			syserr("readqf: no control file %s", qf);
1582		return FALSE;
1583	}
1584
1585	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1586	{
1587		/* being processed by another queuer */
1588		if (Verbose || tTd(40, 8))
1589			printf("%s: locked\n", e->e_id);
1590		if (LogLevel > 19)
1591			sm_syslog(LOG_DEBUG, e->e_id, "locked");
1592		(void) fclose(qfp);
1593		return FALSE;
1594	}
1595
1596	/*
1597	**  Check the queue file for plausibility to avoid attacks.
1598	*/
1599
1600	if (fstat(fileno(qfp), &st) < 0)
1601	{
1602		/* must have been being processed by someone else */
1603		if (tTd(40, 8))
1604			printf("readqf(%s): fstat failure (%s)\n",
1605				qf, errstring(errno));
1606		fclose(qfp);
1607		return FALSE;
1608	}
1609
1610	if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
1611	    bitset(S_IWOTH|S_IWGRP, st.st_mode))
1612	{
1613		if (LogLevel > 0)
1614		{
1615			sm_syslog(LOG_ALERT, e->e_id,
1616				"bogus queue file, uid=%d, mode=%o",
1617				st.st_uid, st.st_mode);
1618		}
1619		if (tTd(40, 8))
1620			printf("readqf(%s): bogus file\n", qf);
1621		loseqfile(e, "bogus file uid in mqueue");
1622		fclose(qfp);
1623		return FALSE;
1624	}
1625
1626	if (st.st_size == 0)
1627	{
1628		/* must be a bogus file -- if also old, just remove it */
1629		if (st.st_ctime + 10 * 60 < curtime())
1630		{
1631			qf[0] = 'd';
1632			(void) unlink(qf);
1633			qf[0] = 'q';
1634			(void) unlink(qf);
1635		}
1636		fclose(qfp);
1637		return FALSE;
1638	}
1639
1640	if (st.st_nlink == 0)
1641	{
1642		/*
1643		**  Race condition -- we got a file just as it was being
1644		**  unlinked.  Just assume it is zero length.
1645		*/
1646
1647		fclose(qfp);
1648		return FALSE;
1649	}
1650
1651	/* good file -- save this lock */
1652	e->e_lockfp = qfp;
1653
1654	/* do basic system initialization */
1655	initsys(e);
1656	define('i', e->e_id, e);
1657
1658	LineNumber = 0;
1659	e->e_flags |= EF_GLOBALERRS;
1660	OpMode = MD_DELIVER;
1661	ctladdr = NULL;
1662	e->e_dfino = -1;
1663	e->e_msgsize = -1;
1664	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1665	{
1666		register char *p;
1667		u_long qflags;
1668		ADDRESS *q;
1669		int mid;
1670		auto char *ep;
1671
1672		if (tTd(40, 4))
1673			printf("+++++ %s\n", bp);
1674		if (nomore)
1675		{
1676			/* hack attack */
1677			syserr("SECURITY ALERT: extra data in qf: %s", bp);
1678			fclose(qfp);
1679			loseqfile(e, "bogus queue line");
1680			return FALSE;
1681		}
1682		switch (bp[0])
1683		{
1684		  case 'V':		/* queue file version number */
1685			qfver = atoi(&bp[1]);
1686			if (qfver <= QF_VERSION)
1687				break;
1688			syserr("Version number in qf (%d) greater than max (%d)",
1689				qfver, QF_VERSION);
1690			fclose(qfp);
1691			loseqfile(e, "unsupported qf file version");
1692			return FALSE;
1693
1694		  case 'C':		/* specify controlling user */
1695			ctladdr = setctluser(&bp[1], qfver);
1696			break;
1697
1698		  case 'Q':		/* original recipient */
1699			orcpt = newstr(&bp[1]);
1700			break;
1701
1702		  case 'R':		/* specify recipient */
1703			p = bp;
1704			qflags = 0;
1705			if (qfver >= 1)
1706			{
1707				/* get flag bits */
1708				while (*++p != '\0' && *p != ':')
1709				{
1710					switch (*p)
1711					{
1712					  case 'N':
1713						qflags |= QHASNOTIFY;
1714						break;
1715
1716					  case 'S':
1717						qflags |= QPINGONSUCCESS;
1718						break;
1719
1720					  case 'F':
1721						qflags |= QPINGONFAILURE;
1722						break;
1723
1724					  case 'D':
1725						qflags |= QPINGONDELAY;
1726						break;
1727
1728					  case 'P':
1729						qflags |= QPRIMARY;
1730						break;
1731					}
1732				}
1733			}
1734			else
1735				qflags |= QPRIMARY;
1736			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
1737			if (q != NULL)
1738			{
1739				q->q_alias = ctladdr;
1740				if (qfver >= 1)
1741					q->q_flags &= ~Q_PINGFLAGS;
1742				q->q_flags |= qflags;
1743				q->q_orcpt = orcpt;
1744				(void) recipient(q, &e->e_sendqueue, 0, e);
1745			}
1746			orcpt = NULL;
1747			break;
1748
1749		  case 'E':		/* specify error recipient */
1750			/* no longer used */
1751			break;
1752
1753		  case 'H':		/* header */
1754			(void) chompheader(&bp[1], FALSE, NULL, e);
1755			hdrsize += strlen(&bp[1]);
1756			break;
1757
1758		  case 'L':		/* Solaris Content-Length: */
1759		  case 'M':		/* message */
1760			/* ignore this; we want a new message next time */
1761			break;
1762
1763		  case 'S':		/* sender */
1764			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
1765			break;
1766
1767		  case 'B':		/* body type */
1768			e->e_bodytype = newstr(&bp[1]);
1769			break;
1770
1771#if _FFR_SAVE_CHARSET
1772		  case 'X':		/* character set */
1773			e->e_charset = newstr(&bp[1]);
1774			break;
1775#endif
1776
1777		  case 'D':		/* data file name */
1778			/* obsolete -- ignore */
1779			break;
1780
1781		  case 'T':		/* init time */
1782			e->e_ctime = atol(&bp[1]);
1783			break;
1784
1785		  case 'I':		/* data file's inode number */
1786			/* regenerated below */
1787			break;
1788
1789		  case 'K':		/* time of last deliver attempt */
1790			e->e_dtime = atol(&buf[1]);
1791			break;
1792
1793		  case 'N':		/* number of delivery attempts */
1794			e->e_ntries = atoi(&buf[1]);
1795
1796			/* if this has been tried recently, let it be */
1797			if (e->e_ntries > 0 &&
1798			    MinQueueAge > 0 && e->e_dtime <= curtime() &&
1799			    curtime() < e->e_dtime + MinQueueAge)
1800			{
1801				char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
1802
1803				if (Verbose || tTd(40, 8))
1804					printf("%s: too young (%s)\n",
1805						e->e_id, howlong);
1806				if (LogLevel > 19)
1807					sm_syslog(LOG_DEBUG, e->e_id,
1808						"too young (%s)",
1809						howlong);
1810				e->e_id = NULL;
1811				unlockqueue(e);
1812				return FALSE;
1813			}
1814			break;
1815
1816		  case 'P':		/* message priority */
1817			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
1818			break;
1819
1820		  case 'F':		/* flag bits */
1821			if (strncmp(bp, "From ", 5) == 0)
1822			{
1823				/* we are being spoofed! */
1824				syserr("SECURITY ALERT: bogus qf line %s", bp);
1825				fclose(qfp);
1826				loseqfile(e, "bogus queue line");
1827				return FALSE;
1828			}
1829			for (p = &bp[1]; *p != '\0'; p++)
1830			{
1831				switch (*p)
1832				{
1833				  case 'w':	/* warning sent */
1834					e->e_flags |= EF_WARNING;
1835					break;
1836
1837				  case 'r':	/* response */
1838					e->e_flags |= EF_RESPONSE;
1839					break;
1840
1841				  case '8':	/* has 8 bit data */
1842					e->e_flags |= EF_HAS8BIT;
1843					break;
1844
1845				  case 'b':	/* delete Bcc: header */
1846					e->e_flags |= EF_DELETE_BCC;
1847					break;
1848
1849				  case 'd':	/* envelope has DSN RET= */
1850					e->e_flags |= EF_RET_PARAM;
1851					break;
1852
1853				  case 'n':	/* don't return body */
1854					e->e_flags |= EF_NO_BODY_RETN;
1855					break;
1856				}
1857			}
1858			break;
1859
1860		  case 'Z':		/* original envelope id from ESMTP */
1861			e->e_envid = newstr(&bp[1]);
1862			break;
1863
1864		  case '$':		/* define macro */
1865			mid = macid(&bp[1], &ep);
1866			define(mid, newstr(ep), e);
1867			break;
1868
1869		  case '.':		/* terminate file */
1870			nomore = TRUE;
1871			break;
1872
1873		  default:
1874			syserr("readqf: %s: line %d: bad line \"%s\"",
1875				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
1876			fclose(qfp);
1877			loseqfile(e, "unrecognized line");
1878			return FALSE;
1879		}
1880
1881		if (bp != buf)
1882			free(bp);
1883	}
1884
1885	/*
1886	**  If we haven't read any lines, this queue file is empty.
1887	**  Arrange to remove it without referencing any null pointers.
1888	*/
1889
1890	if (LineNumber == 0)
1891	{
1892		errno = 0;
1893		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1894		return TRUE;
1895	}
1896
1897	/*
1898	**  Arrange to read the data file.
1899	*/
1900
1901	p = queuename(e, 'd');
1902	e->e_dfp = fopen(p, "r");
1903	if (e->e_dfp == NULL)
1904	{
1905		syserr("readqf: cannot open %s", p);
1906	}
1907	else
1908	{
1909		e->e_flags |= EF_HAS_DF;
1910		if (fstat(fileno(e->e_dfp), &st) >= 0)
1911		{
1912			e->e_msgsize = st.st_size + hdrsize;
1913			e->e_dfdev = st.st_dev;
1914			e->e_dfino = st.st_ino;
1915		}
1916	}
1917
1918	return TRUE;
1919}
1920/*
1921**  PRINTQUEUE -- print out a representation of the mail queue
1922**
1923**	Parameters:
1924**		none.
1925**
1926**	Returns:
1927**		none.
1928**
1929**	Side Effects:
1930**		Prints a listing of the mail queue on the standard output.
1931*/
1932
1933void
1934printqueue()
1935{
1936	register WORK *w;
1937	FILE *f;
1938	int nrequests;
1939	char buf[MAXLINE];
1940
1941	/*
1942	**  Check for permission to print the queue
1943	*/
1944
1945	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
1946	{
1947		struct stat st;
1948# ifdef NGROUPS_MAX
1949		int n;
1950		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
1951# endif
1952
1953		if (stat(QueueDir, &st) < 0)
1954		{
1955			syserr("Cannot stat %s", QueueDir);
1956			return;
1957		}
1958# ifdef NGROUPS_MAX
1959		n = NGROUPS_MAX;
1960		while (--n >= 0)
1961		{
1962			if (InitialGidSet[n] == st.st_gid)
1963				break;
1964		}
1965		if (n < 0 && RealGid != st.st_gid)
1966# else
1967		if (RealGid != st.st_gid)
1968# endif
1969		{
1970			usrerr("510 You are not permitted to see the queue");
1971			setstat(EX_NOPERM);
1972			return;
1973		}
1974	}
1975
1976	/*
1977	**  Read and order the queue.
1978	*/
1979
1980	nrequests = orderq(TRUE);
1981
1982	/*
1983	**  Print the work list that we have read.
1984	*/
1985
1986	/* first see if there is anything */
1987	if (nrequests <= 0)
1988	{
1989		printf("Mail queue is empty\n");
1990		return;
1991	}
1992
1993	CurrentLA = getla();	/* get load average */
1994
1995	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
1996	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
1997		printf(", only %d printed", MaxQueueRun);
1998	if (Verbose)
1999		printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
2000	else
2001		printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
2002	for (w = WorkQ; w != NULL; w = w->w_next)
2003	{
2004		struct stat st;
2005		auto time_t submittime = 0;
2006		long dfsize;
2007		int flags = 0;
2008		int qfver;
2009		char statmsg[MAXLINE];
2010		char bodytype[MAXNAME + 1];
2011
2012		printf("%8s", w->w_name + 2);
2013		f = fopen(w->w_name, "r");
2014		if (f == NULL)
2015		{
2016			printf(" (job completed)\n");
2017			errno = 0;
2018			continue;
2019		}
2020		w->w_name[0] = 'd';
2021		if (stat(w->w_name, &st) >= 0)
2022			dfsize = st.st_size;
2023		else
2024			dfsize = -1;
2025		if (w->w_lock)
2026			printf("*");
2027		else if (w->w_tooyoung)
2028			printf("-");
2029		else if (shouldqueue(w->w_pri, w->w_ctime))
2030			printf("X");
2031		else
2032			printf(" ");
2033		errno = 0;
2034
2035		statmsg[0] = bodytype[0] = '\0';
2036		qfver = 0;
2037		while (fgets(buf, sizeof buf, f) != NULL)
2038		{
2039			register int i;
2040			register char *p;
2041
2042			fixcrlf(buf, TRUE);
2043			switch (buf[0])
2044			{
2045			  case 'V':	/* queue file version */
2046				qfver = atoi(&buf[1]);
2047				break;
2048
2049			  case 'M':	/* error message */
2050				if ((i = strlen(&buf[1])) >= sizeof statmsg)
2051					i = sizeof statmsg - 1;
2052				bcopy(&buf[1], statmsg, i);
2053				statmsg[i] = '\0';
2054				break;
2055
2056			  case 'B':	/* body type */
2057				if ((i = strlen(&buf[1])) >= sizeof bodytype)
2058					i = sizeof bodytype - 1;
2059				bcopy(&buf[1], bodytype, i);
2060				bodytype[i] = '\0';
2061				break;
2062
2063			  case 'S':	/* sender name */
2064				if (Verbose)
2065					printf("%8ld %10ld%c%.12s %.78s",
2066					    dfsize,
2067					    w->w_pri,
2068					    bitset(EF_WARNING, flags) ? '+' : ' ',
2069					    ctime(&submittime) + 4,
2070					    &buf[1]);
2071				else
2072					printf("%8ld %.16s %.45s", dfsize,
2073					    ctime(&submittime), &buf[1]);
2074				if (statmsg[0] != '\0' || bodytype[0] != '\0')
2075				{
2076					printf("\n    %10.10s", bodytype);
2077					if (statmsg[0] != '\0')
2078						printf("   (%.*s)",
2079							Verbose ? 100 : 60,
2080							statmsg);
2081				}
2082				break;
2083
2084			  case 'C':	/* controlling user */
2085				if (Verbose)
2086					printf("\n\t\t\t\t      (---%.74s---)",
2087						&buf[1]);
2088				break;
2089
2090			  case 'R':	/* recipient name */
2091				p = &buf[1];
2092				if (qfver >= 1)
2093				{
2094					p = strchr(p, ':');
2095					if (p == NULL)
2096						break;
2097					p++;
2098				}
2099				if (Verbose)
2100					printf("\n\t\t\t\t\t  %.78s", p);
2101				else
2102					printf("\n\t\t\t\t   %.45s", p);
2103				break;
2104
2105			  case 'T':	/* creation time */
2106				submittime = atol(&buf[1]);
2107				break;
2108
2109			  case 'F':	/* flag bits */
2110				for (p = &buf[1]; *p != '\0'; p++)
2111				{
2112					switch (*p)
2113					{
2114					  case 'w':
2115						flags |= EF_WARNING;
2116						break;
2117					}
2118				}
2119			}
2120		}
2121		if (submittime == (time_t) 0)
2122			printf(" (no control file)");
2123		printf("\n");
2124		(void) fclose(f);
2125	}
2126}
2127
2128# endif /* QUEUE */
2129/*
2130**  QUEUENAME -- build a file name in the queue directory for this envelope.
2131**
2132**	Assigns an id code if one does not already exist.
2133**	This code is very careful to avoid trashing existing files
2134**	under any circumstances.
2135**
2136**	Parameters:
2137**		e -- envelope to build it in/from.
2138**		type -- the file type, used as the first character
2139**			of the file name.
2140**
2141**	Returns:
2142**		a pointer to the new file name (in a static buffer).
2143**
2144**	Side Effects:
2145**		If no id code is already assigned, queuename will
2146**		assign an id code, create a qf file, and leave a
2147**		locked, open-for-write file pointer in the envelope.
2148*/
2149
2150#ifndef ENOLCK
2151# define ENOLCK		-1
2152#endif
2153#ifndef ENOSPC
2154# define ENOSPC		-1
2155#endif
2156
2157char *
2158queuename(e, type)
2159	register ENVELOPE *e;
2160	int type;
2161{
2162	static pid_t pid = -1;
2163	static char c0;
2164	static char c1;
2165	static char c2;
2166	time_t now;
2167	struct tm *tm;
2168	static char buf[MAXNAME + 1];
2169
2170	if (e->e_id == NULL)
2171	{
2172		char qf[MAXQFNAME];
2173
2174		/* find a unique id */
2175		if (pid != getpid())
2176		{
2177			/* new process -- start back at "AA" */
2178			pid = getpid();
2179			now = curtime();
2180			tm = localtime(&now);
2181			c0 = 'A' + tm->tm_hour;
2182			c1 = 'A';
2183			c2 = 'A' - 1;
2184		}
2185		(void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid);
2186
2187		while (c1 < '~' || c2 < 'Z')
2188		{
2189			int i;
2190			int attempts = 0;
2191
2192			if (c2 >= 'Z')
2193			{
2194				c1++;
2195				c2 = 'A' - 1;
2196			}
2197			qf[3] = c1;
2198			qf[4] = ++c2;
2199			if (tTd(7, 20))
2200				printf("queuename: trying \"%s\"\n", qf);
2201
2202			i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
2203			if (i < 0)
2204			{
2205				if (errno == EEXIST)
2206					continue;
2207				syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2208					qf, QueueDir, geteuid());
2209				finis(FALSE, EX_UNAVAILABLE);
2210			}
2211			do
2212			{
2213				if (attempts > 0)
2214					sleep(attempts);
2215				e->e_lockfp = 0;
2216				if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
2217				{
2218					e->e_lockfp = fdopen(i, "w");
2219					break;
2220				}
2221			} while ((errno == ENOLCK || errno == ENOSPC) &&
2222				 attempts++ < 4);
2223
2224			/* Successful lock */
2225			if (e->e_lockfp != 0)
2226				break;
2227
2228#if !HASFLOCK
2229			if (errno != EAGAIN && errno != EACCES)
2230#else
2231			if (errno != EWOULDBLOCK)
2232#endif
2233			{
2234				syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)",
2235					qf, QueueDir, geteuid());
2236				finis(FALSE, EX_OSERR);
2237			}
2238
2239			/* a reader got the file; abandon it and try again */
2240			(void) close(i);
2241		}
2242		if (c1 >= '~' && c2 >= 'Z')
2243		{
2244			syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2245				qf, QueueDir, geteuid());
2246			finis(FALSE, EX_OSERR);
2247		}
2248		e->e_id = newstr(&qf[2]);
2249		define('i', e->e_id, e);
2250		if (tTd(7, 1))
2251			printf("queuename: assigned id %s, env=%lx\n",
2252			       e->e_id, (u_long) e);
2253		if (tTd(7, 9))
2254		{
2255			printf("  lockfd=");
2256			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
2257		}
2258		if (LogLevel > 93)
2259			sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
2260	}
2261
2262	if (type == '\0')
2263		return (NULL);
2264	(void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id);
2265	if (tTd(7, 2))
2266		printf("queuename: %s\n", buf);
2267	return (buf);
2268}
2269/*
2270**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
2271**
2272**	Parameters:
2273**		e -- the envelope to unlock.
2274**
2275**	Returns:
2276**		none
2277**
2278**	Side Effects:
2279**		unlocks the queue for `e'.
2280*/
2281
2282void
2283unlockqueue(e)
2284	ENVELOPE *e;
2285{
2286	if (tTd(51, 4))
2287		printf("unlockqueue(%s)\n",
2288			e->e_id == NULL ? "NOQUEUE" : e->e_id);
2289
2290	/* if there is a lock file in the envelope, close it */
2291	if (e->e_lockfp != NULL)
2292		xfclose(e->e_lockfp, "unlockqueue", e->e_id);
2293	e->e_lockfp = NULL;
2294
2295	/* don't create a queue id if we don't already have one */
2296	if (e->e_id == NULL)
2297		return;
2298
2299	/* remove the transcript */
2300	if (LogLevel > 87)
2301		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
2302	if (!tTd(51, 104))
2303		xunlink(queuename(e, 'x'));
2304
2305}
2306/*
2307**  SETCTLUSER -- create a controlling address
2308**
2309**	Create a fake "address" given only a local login name; this is
2310**	used as a "controlling user" for future recipient addresses.
2311**
2312**	Parameters:
2313**		user -- the user name of the controlling user.
2314**		qfver -- the version stamp of this qf file.
2315**
2316**	Returns:
2317**		An address descriptor for the controlling user.
2318**
2319**	Side Effects:
2320**		none.
2321*/
2322
2323ADDRESS *
2324setctluser(user, qfver)
2325	char *user;
2326	int qfver;
2327{
2328	register ADDRESS *a;
2329	struct passwd *pw;
2330	char *p;
2331
2332	/*
2333	**  See if this clears our concept of controlling user.
2334	*/
2335
2336	if (user == NULL || *user == '\0')
2337		return NULL;
2338
2339	/*
2340	**  Set up addr fields for controlling user.
2341	*/
2342
2343	a = (ADDRESS *) xalloc(sizeof *a);
2344	bzero((char *) a, sizeof *a);
2345
2346	if (*user == '\0')
2347	{
2348		p = NULL;
2349		a->q_user = newstr(DefUser);
2350	}
2351	else if (*user == ':')
2352	{
2353		p = &user[1];
2354		a->q_user = newstr(p);
2355	}
2356	else
2357	{
2358		p = strtok(user, ":");
2359		a->q_user = newstr(user);
2360		if (qfver >= 2)
2361		{
2362			if ((p = strtok(NULL, ":")) != NULL)
2363				a->q_uid = atoi(p);
2364			if ((p = strtok(NULL, ":")) != NULL)
2365				a->q_gid = atoi(p);
2366			if ((p = strtok(NULL, ":")) != NULL)
2367				a->q_flags |= QGOODUID;
2368		}
2369		else if ((pw = sm_getpwnam(user)) != NULL)
2370		{
2371			if (strcmp(pw->pw_dir, "/") == 0)
2372				a->q_home = "";
2373			else
2374				a->q_home = newstr(pw->pw_dir);
2375			a->q_uid = pw->pw_uid;
2376			a->q_gid = pw->pw_gid;
2377			a->q_flags |= QGOODUID;
2378		}
2379	}
2380
2381	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr"  */
2382	a->q_mailer = LocalMailer;
2383	if (p == NULL)
2384		a->q_paddr = a->q_user;
2385	else
2386		a->q_paddr = newstr(p);
2387	return a;
2388}
2389/*
2390**  LOSEQFILE -- save the qf as Qf and try to let someone know
2391**
2392**	Parameters:
2393**		e -- the envelope (e->e_id will be used).
2394**		why -- reported to whomever can hear.
2395**
2396**	Returns:
2397**		none.
2398*/
2399
2400void
2401loseqfile(e, why)
2402	register ENVELOPE *e;
2403	char *why;
2404{
2405	char *p;
2406	char buf[MAXQFNAME + 1];
2407
2408	if (e == NULL || e->e_id == NULL)
2409		return;
2410	p = queuename(e, 'q');
2411	if (strlen(p) > MAXQFNAME)
2412	{
2413		syserr("loseqfile: queuename (%s) too long", p);
2414		return;
2415	}
2416	strcpy(buf, p);
2417	p = queuename(e, 'Q');
2418	if (rename(buf, p) < 0)
2419		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2420	else if (LogLevel > 0)
2421		sm_syslog(LOG_ALERT, e->e_id,
2422			"Losing %s: %s", buf, why);
2423}
2424