xref: /freebsd/contrib/sendmail/src/queue.c (revision 04c9749ff0148ec8f73b150cec8bc2c094a5d31a)
1 /*
2  * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13 
14 
15 #include <sendmail.h>
16 
17 #ifndef lint
18 # if QUEUE
19 static char id[] = "@(#)$Id: queue.c,v 8.343.4.11 2000/07/14 05:55:51 gshapiro Exp $ (with queueing)";
20 # else /* QUEUE */
21 static char id[] = "@(#)$Id: queue.c,v 8.343.4.11 2000/07/14 05:55:51 gshapiro Exp $ (without queueing)";
22 # endif /* QUEUE */
23 #endif /* ! lint */
24 
25 # include <dirent.h>
26 
27 #if QUEUE
28 
29 # if _FFR_QUEUEDELAY
30 #  define QF_VERSION	5	/* version number of this queue format */
31 static time_t	queuedelay __P((ENVELOPE *));
32 # else /* _FFR_QUEUEDELAY */
33 #  define QF_VERSION	4	/* version number of this queue format */
34 #  define queuedelay(e)	MinQueueAge
35 # endif /* _FFR_QUEUEDELAY */
36 
37 /*
38 **  Work queue.
39 */
40 
41 struct work
42 {
43 	char		*w_name;	/* name of control file */
44 	char		*w_host;	/* name of recipient host */
45 	bool		w_lock;		/* is message locked? */
46 	bool		w_tooyoung;	/* is it too young to run? */
47 	long		w_pri;		/* priority of message, see below */
48 	time_t		w_ctime;	/* creation time of message */
49 	struct work	*w_next;	/* next in queue */
50 };
51 
52 typedef struct work	WORK;
53 
54 static WORK	*WorkQ;			/* queue of things to be done */
55 
56 static void	grow_wlist __P((int));
57 static int	orderq __P((int, bool));
58 static void	printctladdr __P((ADDRESS *, FILE *));
59 static int	print_single_queue __P((int));
60 static bool	readqf __P((ENVELOPE *));
61 static void	runqueueevent __P((void));
62 static int	run_single_queue __P((int, bool, bool));
63 static char	*strrev __P((char *));
64 static ADDRESS	*setctluser __P((char *, int));
65 static int	workcmpf0();
66 static int	workcmpf1();
67 static int	workcmpf2();
68 static int	workcmpf3();
69 static int	workcmpf4();
70 
71 /*
72 **  QUEUEUP -- queue a message up for future transmission.
73 **
74 **	Parameters:
75 **		e -- the envelope to queue up.
76 **		announce -- if TRUE, tell when you are queueing up.
77 **
78 **	Returns:
79 **		none.
80 **
81 **	Side Effects:
82 **		The current request are saved in a control file.
83 **		The queue file is left locked.
84 */
85 
86 # define TEMPQF_LETTER 'T'
87 
88 void
89 queueup(e, announce)
90 	register ENVELOPE *e;
91 	bool announce;
92 {
93 	char *qf;
94 	register FILE *tfp;
95 	register HDR *h;
96 	register ADDRESS *q;
97 	int tfd = -1;
98 	int i;
99 	bool newid;
100 	register char *p;
101 	MAILER nullmailer;
102 	MCI mcibuf;
103 	char tf[MAXPATHLEN];
104 	char buf[MAXLINE];
105 
106 	/*
107 	**  Create control file.
108 	*/
109 
110 	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
111 
112 	/* if newid, queuename will create a locked qf file in e->lockfp */
113 	(void) strlcpy(tf, queuename(e, 't'), sizeof tf);
114 	tfp = e->e_lockfp;
115 	if (tfp == NULL)
116 		newid = FALSE;
117 
118 	/* if newid, just write the qf file directly (instead of tf file) */
119 	if (!newid)
120 	{
121 		int flags;
122 
123 		flags = O_CREAT|O_WRONLY|O_EXCL;
124 
125 		/* get a locked tf file */
126 		for (i = 0; i < 128; i++)
127 		{
128 			if (tfd < 0)
129 			{
130 #if _FFR_QUEUE_FILE_MODE
131 				MODE_T oldumask;
132 
133 				if (bitset(S_IWGRP, QueueFileMode))
134 					oldumask = umask(002);
135 				tfd = open(tf, flags, QueueFileMode);
136 				if (bitset(S_IWGRP, QueueFileMode))
137 					(void) umask(oldumask);
138 #else /* _FFR_QUEUE_FILE_MODE */
139 				tfd = open(tf, flags, FileMode);
140 #endif /* _FFR_QUEUE_FILE_MODE */
141 
142 				if (tfd < 0)
143 				{
144 					if (errno != EEXIST)
145 						break;
146 					if (LogLevel > 0 && (i % 32) == 0)
147 						sm_syslog(LOG_ALERT, e->e_id,
148 							  "queueup: cannot create %s, uid=%d: %s",
149 							  tf, geteuid(), errstring(errno));
150 				}
151 			}
152 			if (tfd >= 0)
153 			{
154 				if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
155 					break;
156 				else if (LogLevel > 0 && (i % 32) == 0)
157 					sm_syslog(LOG_ALERT, e->e_id,
158 						  "queueup: cannot lock %s: %s",
159 						  tf, errstring(errno));
160 				if ((i % 32) == 31)
161 				{
162 					(void) close(tfd);
163 					tfd = -1;
164 				}
165 			}
166 
167 			if ((i % 32) == 31)
168 			{
169 				/* save the old temp file away */
170 				(void) rename(tf, queuename(e, TEMPQF_LETTER));
171 			}
172 			else
173 				(void) sleep(i % 32);
174 		}
175 		if (tfd < 0 || (tfp = fdopen(tfd, "w")) == NULL)
176 		{
177 			int save_errno = errno;
178 
179 			printopenfds(TRUE);
180 			errno = save_errno;
181 			syserr("!queueup: cannot create queue temp file %s, uid=%d",
182 				tf, geteuid());
183 		}
184 	}
185 
186 	if (tTd(40, 1))
187 		dprintf("\n>>>>> queueing %s/qf%s%s >>>>>\n",
188 			qid_printqueue(e->e_queuedir), e->e_id,
189 			newid ? " (new id)" : "");
190 	if (tTd(40, 3))
191 	{
192 		dprintf("  e_flags=");
193 		printenvflags(e);
194 	}
195 	if (tTd(40, 32))
196 	{
197 		dprintf("  sendq=");
198 		printaddr(e->e_sendqueue, TRUE);
199 	}
200 	if (tTd(40, 9))
201 	{
202 		dprintf("  tfp=");
203 		dumpfd(fileno(tfp), TRUE, FALSE);
204 		dprintf("  lockfp=");
205 		if (e->e_lockfp == NULL)
206 			dprintf("NULL\n");
207 		else
208 			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
209 	}
210 
211 	/*
212 	**  If there is no data file yet, create one.
213 	*/
214 
215 	if (bitset(EF_HAS_DF, e->e_flags))
216 	{
217 		if (e->e_dfp != NULL && bfcommit(e->e_dfp) < 0)
218 			syserr("!queueup: cannot commit data file %s, uid=%d",
219 				queuename(e, 'd'), geteuid());
220 	}
221 	else
222 	{
223 		int dfd;
224 		register FILE *dfp = NULL;
225 		char dfname[MAXPATHLEN];
226 		struct stat stbuf;
227 
228 		if (e->e_dfp != NULL && bftest(e->e_dfp))
229 			syserr("committing over bf file");
230 
231 		(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
232 #if _FFR_QUEUE_FILE_MODE
233 		{
234 			MODE_T oldumask;
235 
236 			if (bitset(S_IWGRP, QueueFileMode))
237 				oldumask = umask(002);
238 			dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC,
239 				   QueueFileMode);
240 			if (bitset(S_IWGRP, QueueFileMode))
241 				(void) umask(oldumask);
242 		}
243 #else /* _FFR_QUEUE_FILE_MODE */
244 		dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
245 #endif /* _FFR_QUEUE_FILE_MODE */
246 		if (dfd < 0 || (dfp = fdopen(dfd, "w")) == NULL)
247 			syserr("!queueup: cannot create data temp file %s, uid=%d",
248 				dfname, geteuid());
249 		if (fstat(dfd, &stbuf) < 0)
250 			e->e_dfino = -1;
251 		else
252 		{
253 			e->e_dfdev = stbuf.st_dev;
254 			e->e_dfino = stbuf.st_ino;
255 		}
256 		e->e_flags |= EF_HAS_DF;
257 		memset(&mcibuf, '\0', sizeof mcibuf);
258 		mcibuf.mci_out = dfp;
259 		mcibuf.mci_mailer = FileMailer;
260 		(*e->e_putbody)(&mcibuf, e, NULL);
261 		if (fclose(dfp) < 0)
262 			syserr("!queueup: cannot save data temp file %s, uid=%d",
263 				dfname, geteuid());
264 		e->e_putbody = putbody;
265 	}
266 
267 	/*
268 	**  Output future work requests.
269 	**	Priority and creation time should be first, since
270 	**	they are required by orderq.
271 	*/
272 
273 	/* output queue version number (must be first!) */
274 	fprintf(tfp, "V%d\n", QF_VERSION);
275 
276 	/* output creation time */
277 	fprintf(tfp, "T%ld\n", (long) e->e_ctime);
278 
279 	/* output last delivery time */
280 # if _FFR_QUEUEDELAY
281 	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
282 	fprintf(tfp, "G%d\n", e->e_queuealg);
283 	fprintf(tfp, "Y%ld\n", (long) e->e_queuedelay);
284 	if (tTd(40, 64))
285 		sm_syslog(LOG_INFO, e->e_id,
286 			"queue alg: %d delay %ld next: %ld (now: %ld)\n",
287 			e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime());
288 # else /* _FFR_QUEUEDELAY */
289 	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
290 # endif /* _FFR_QUEUEDELAY */
291 
292 	/* output number of delivery attempts */
293 	fprintf(tfp, "N%d\n", e->e_ntries);
294 
295 	/* output message priority */
296 	fprintf(tfp, "P%ld\n", e->e_msgpriority);
297 
298 	/* output inode number of data file */
299 	/* XXX should probably include device major/minor too */
300 	if (e->e_dfino != -1)
301 	{
302 		/*CONSTCOND*/
303 		if (sizeof e->e_dfino > sizeof(long))
304 			fprintf(tfp, "I%ld/%ld/%s\n",
305 				(long) major(e->e_dfdev),
306 				(long) minor(e->e_dfdev),
307 				quad_to_string(e->e_dfino));
308 		else
309 			fprintf(tfp, "I%ld/%ld/%lu\n",
310 				(long) major(e->e_dfdev),
311 				(long) minor(e->e_dfdev),
312 				(unsigned long) e->e_dfino);
313 	}
314 
315 	/* output body type */
316 	if (e->e_bodytype != NULL)
317 		fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
318 
319 # if _FFR_SAVE_CHARSET
320 	if (e->e_charset != NULL)
321 		fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
322 # endif /* _FFR_SAVE_CHARSET */
323 
324 	/* message from envelope, if it exists */
325 	if (e->e_message != NULL)
326 		fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
327 
328 	/* send various flag bits through */
329 	p = buf;
330 	if (bitset(EF_WARNING, e->e_flags))
331 		*p++ = 'w';
332 	if (bitset(EF_RESPONSE, e->e_flags))
333 		*p++ = 'r';
334 	if (bitset(EF_HAS8BIT, e->e_flags))
335 		*p++ = '8';
336 	if (bitset(EF_DELETE_BCC, e->e_flags))
337 		*p++ = 'b';
338 	if (bitset(EF_RET_PARAM, e->e_flags))
339 		*p++ = 'd';
340 	if (bitset(EF_NO_BODY_RETN, e->e_flags))
341 		*p++ = 'n';
342 	*p++ = '\0';
343 	if (buf[0] != '\0')
344 		fprintf(tfp, "F%s\n", buf);
345 
346 	/* save $={persistentMacros} macro values */
347 	queueup_macros(macid("{persistentMacros}", NULL), tfp, e);
348 
349 	/* output name of sender */
350 	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
351 		p = e->e_sender;
352 	else
353 		p = e->e_from.q_paddr;
354 	fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
355 
356 	/* output ESMTP-supplied "original" information */
357 	if (e->e_envid != NULL)
358 		fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
359 
360 	/* output AUTH= parameter */
361 	if (e->e_auth_param != NULL)
362 		fprintf(tfp, "A%s\n", denlstring(e->e_auth_param,
363 						 TRUE, FALSE));
364 
365 	/* output list of recipient addresses */
366 	printctladdr(NULL, NULL);
367 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
368 	{
369 		if (!QS_IS_UNDELIVERED(q->q_state))
370 			continue;
371 
372 		printctladdr(q, tfp);
373 		if (q->q_orcpt != NULL)
374 			fprintf(tfp, "Q%s\n",
375 				denlstring(q->q_orcpt, TRUE, FALSE));
376 		(void) putc('R', tfp);
377 		if (bitset(QPRIMARY, q->q_flags))
378 			(void) putc('P', tfp);
379 		if (bitset(QHASNOTIFY, q->q_flags))
380 			(void) putc('N', tfp);
381 		if (bitset(QPINGONSUCCESS, q->q_flags))
382 			(void) putc('S', tfp);
383 		if (bitset(QPINGONFAILURE, q->q_flags))
384 			(void) putc('F', tfp);
385 		if (bitset(QPINGONDELAY, q->q_flags))
386 			(void) putc('D', tfp);
387 		(void) putc(':', tfp);
388 		(void) fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
389 		if (announce)
390 		{
391 			e->e_to = q->q_paddr;
392 			message("queued");
393 			if (LogLevel > 8)
394 				logdelivery(q->q_mailer, NULL, q->q_status,
395 					    "queued", NULL, (time_t) 0, e);
396 			e->e_to = NULL;
397 		}
398 		if (tTd(40, 1))
399 		{
400 			dprintf("queueing ");
401 			printaddr(q, FALSE);
402 		}
403 	}
404 
405 	/*
406 	**  Output headers for this message.
407 	**	Expand macros completely here.  Queue run will deal with
408 	**	everything as absolute headers.
409 	**		All headers that must be relative to the recipient
410 	**		can be cracked later.
411 	**	We set up a "null mailer" -- i.e., a mailer that will have
412 	**	no effect on the addresses as they are output.
413 	*/
414 
415 	memset((char *) &nullmailer, '\0', sizeof nullmailer);
416 	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
417 			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
418 	nullmailer.m_eol = "\n";
419 	memset(&mcibuf, '\0', sizeof mcibuf);
420 	mcibuf.mci_mailer = &nullmailer;
421 	mcibuf.mci_out = tfp;
422 
423 	define('g', "\201f", e);
424 	for (h = e->e_header; h != NULL; h = h->h_link)
425 	{
426 		if (h->h_value == NULL)
427 			continue;
428 
429 		/* don't output resent headers on non-resent messages */
430 		if (bitset(H_RESENT, h->h_flags) &&
431 		    !bitset(EF_RESENT, e->e_flags))
432 			continue;
433 
434 		/* expand macros; if null, don't output header at all */
435 		if (bitset(H_DEFAULT, h->h_flags))
436 		{
437 			(void) expand(h->h_value, buf, sizeof buf, e);
438 			if (buf[0] == '\0')
439 				continue;
440 		}
441 
442 		/* output this header */
443 		fprintf(tfp, "H?");
444 
445 		/* output conditional macro if present */
446 		if (h->h_macro != '\0')
447 		{
448 			if (bitset(0200, h->h_macro))
449 				fprintf(tfp, "${%s}",
450 					macname(h->h_macro & 0377));
451 			else
452 				fprintf(tfp, "$%c", h->h_macro);
453 		}
454 		else if (!bitzerop(h->h_mflags) &&
455 			 bitset(H_CHECK|H_ACHECK, h->h_flags))
456 		{
457 			int j;
458 
459 			/* if conditional, output the set of conditions */
460 			for (j = '\0'; j <= '\177'; j++)
461 				if (bitnset(j, h->h_mflags))
462 					(void) putc(j, tfp);
463 		}
464 		(void) putc('?', tfp);
465 
466 		/* output the header: expand macros, convert addresses */
467 		if (bitset(H_DEFAULT, h->h_flags) &&
468 		    !bitset(H_BINDLATE, h->h_flags))
469 		{
470 			fprintf(tfp, "%s: %s\n",
471 				h->h_field,
472 				denlstring(buf, FALSE, TRUE));
473 		}
474 		else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
475 			 !bitset(H_BINDLATE, h->h_flags))
476 		{
477 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
478 			FILE *savetrace = TrafficLogFile;
479 
480 			TrafficLogFile = NULL;
481 
482 			if (bitset(H_FROM, h->h_flags))
483 				oldstyle = FALSE;
484 
485 			commaize(h, h->h_value, oldstyle, &mcibuf, e);
486 
487 			TrafficLogFile = savetrace;
488 		}
489 		else
490 		{
491 			fprintf(tfp, "%s: %s\n",
492 				h->h_field,
493 				denlstring(h->h_value, FALSE, TRUE));
494 		}
495 	}
496 
497 	/*
498 	**  Clean up.
499 	**
500 	**	Write a terminator record -- this is to prevent
501 	**	scurrilous crackers from appending any data.
502 	*/
503 
504 	fprintf(tfp, ".\n");
505 
506 	if (fflush(tfp) < 0 ||
507 	    (SuperSafe && fsync(fileno(tfp)) < 0) ||
508 	    ferror(tfp))
509 	{
510 		if (newid)
511 			syserr("!552 Error writing control file %s", tf);
512 		else
513 			syserr("!452 Error writing control file %s", tf);
514 	}
515 
516 	if (!newid)
517 	{
518 		/* rename (locked) tf to be (locked) qf */
519 		qf = queuename(e, 'q');
520 		if (rename(tf, qf) < 0)
521 			syserr("cannot rename(%s, %s), uid=%d",
522 				tf, qf, geteuid());
523 
524 		/*
525 		**  fsync() after renaming to make sure
526 		**  metadata is written to disk on
527 		**  filesystems in which renames are
528 		**  not guaranteed such as softupdates.
529 		*/
530 
531 		if (tfd >= 0 && SuperSafe && fsync(tfd) < 0)
532 			syserr("!queueup: cannot fsync queue temp file %s",
533 			       tf);
534 
535 		/* close and unlock old (locked) qf */
536 		if (e->e_lockfp != NULL)
537 			(void) fclose(e->e_lockfp);
538 		e->e_lockfp = tfp;
539 	}
540 	else
541 		qf = tf;
542 	errno = 0;
543 	e->e_flags |= EF_INQUEUE;
544 
545 	/* save log info */
546 	if (LogLevel > 79)
547 		sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
548 
549 	if (tTd(40, 1))
550 		dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
551 	return;
552 }
553 
554 static void
555 printctladdr(a, tfp)
556 	register ADDRESS *a;
557 	FILE *tfp;
558 {
559 	char *user;
560 	register ADDRESS *q;
561 	uid_t uid;
562 	gid_t gid;
563 	static ADDRESS *lastctladdr = NULL;
564 	static uid_t lastuid;
565 
566 	/* initialization */
567 	if (a == NULL || a->q_alias == NULL || tfp == NULL)
568 	{
569 		if (lastctladdr != NULL && tfp != NULL)
570 			fprintf(tfp, "C\n");
571 		lastctladdr = NULL;
572 		lastuid = 0;
573 		return;
574 	}
575 
576 	/* find the active uid */
577 	q = getctladdr(a);
578 	if (q == NULL)
579 	{
580 		user = NULL;
581 		uid = 0;
582 		gid = 0;
583 	}
584 	else
585 	{
586 		user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
587 		uid = q->q_uid;
588 		gid = q->q_gid;
589 	}
590 	a = a->q_alias;
591 
592 	/* check to see if this is the same as last time */
593 	if (lastctladdr != NULL && uid == lastuid &&
594 	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
595 		return;
596 	lastuid = uid;
597 	lastctladdr = a;
598 
599 	if (uid == 0 || user == NULL || user[0] == '\0')
600 		fprintf(tfp, "C");
601 	else
602 		fprintf(tfp, "C%s:%ld:%ld",
603 			denlstring(user, TRUE, FALSE), (long) uid, (long) gid);
604 	fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
605 }
606 /*
607 **  RUNQUEUE -- run the jobs in the queue.
608 **
609 **	Gets the stuff out of the queue in some presumably logical
610 **	order and processes them.
611 **
612 **	Parameters:
613 **		forkflag -- TRUE if the queue scanning should be done in
614 **			a child process.  We double-fork so it is not our
615 **			child and we don't have to clean up after it.
616 **			FALSE can be ignored if we have multiple queues.
617 **		verbose -- if TRUE, print out status information.
618 **
619 **	Returns:
620 **		TRUE if the queue run successfully began.
621 **
622 **	Side Effects:
623 **		runs things in the mail queue.
624 */
625 
626 static ENVELOPE	QueueEnvelope;		/* the queue run envelope */
627 int		NumQueues = 0;		/* number of queues */
628 static time_t	LastQueueTime = 0;	/* last time a queue ID assigned */
629 static pid_t	LastQueuePid = -1;	/* last PID which had a queue ID */
630 
631 struct qpaths_s
632 {
633 	char	*qp_name;	/* name of queue dir */
634 	short	qp_subdirs;	/* use subdirs? */
635 };
636 
637 typedef struct qpaths_s QPATHS;
638 
639 /* values for qp_supdirs */
640 #define QP_NOSUB	0x0000	/* No subdirectories */
641 #define QP_SUBDF	0x0001	/* "df" subdirectory */
642 #define QP_SUBQF	0x0002	/* "qf" subdirectory */
643 #define QP_SUBXF	0x0004	/* "xf" subdirectory */
644 
645 static QPATHS	*QPaths = NULL;		/* list of queue directories */
646 
647 bool
648 runqueue(forkflag, verbose)
649 	bool forkflag;
650 	bool verbose;
651 {
652 	int i;
653 	bool ret = TRUE;
654 	static int curnum = 0;
655 
656 	if (!forkflag && NumQueues > 1 && !verbose)
657 		forkflag = TRUE;
658 
659 	for (i = 0; i < NumQueues; i++)
660 	{
661 		/*
662 		**  Pick up where we left off, in case we
663 		**  used up all the children last time
664 		**  without finishing.
665 		*/
666 
667 		ret = run_single_queue(curnum, forkflag, verbose);
668 
669 		/*
670 		**  Failure means a message was printed for ETRN
671 		**  and subsequent queues are likely to fail as well.
672 		*/
673 
674 		if (!ret)
675 			break;
676 
677 		if (++curnum >= NumQueues)
678 			curnum = 0;
679 	}
680 	if (QueueIntvl != 0)
681 		(void) setevent(QueueIntvl, runqueueevent, 0);
682 	return ret;
683 }
684 /*
685 **  RUN_SINGLE_QUEUE -- run the jobs in a single queue.
686 **
687 **	Gets the stuff out of the queue in some presumably logical
688 **	order and processes them.
689 **
690 **	Parameters:
691 **		queuedir -- queue to process
692 **		forkflag -- TRUE if the queue scanning should be done in
693 **			a child process.  We double-fork so it is not our
694 **			child and we don't have to clean up after it.
695 **		verbose -- if TRUE, print out status information.
696 **
697 **	Returns:
698 **		TRUE if the queue run successfully began.
699 **
700 **	Side Effects:
701 **		runs things in the mail queue.
702 */
703 
704 static bool
705 run_single_queue(queuedir, forkflag, verbose)
706 	int queuedir;
707 	bool forkflag;
708 	bool verbose;
709 {
710 	register ENVELOPE *e;
711 	int njobs;
712 	int sequenceno = 0;
713 	time_t current_la_time;
714 	extern ENVELOPE BlankEnvelope;
715 
716 	DoQueueRun = FALSE;
717 
718 	/*
719 	**  If no work will ever be selected, don't even bother reading
720 	**  the queue.
721 	*/
722 
723 	CurrentLA = sm_getla(NULL);	/* get load average */
724 	current_la_time = curtime();
725 
726 	if (shouldqueue(WkRecipFact, current_la_time))
727 	{
728 		char *msg = "Skipping queue run -- load average too high";
729 
730 		if (verbose)
731 			message("458 %s\n", msg);
732 		if (LogLevel > 8)
733 			sm_syslog(LOG_INFO, NOQID,
734 				  "runqueue: %s",
735 				  msg);
736 		return FALSE;
737 	}
738 
739 	/*
740 	**  See if we already have too many children.
741 	*/
742 
743 	if (forkflag && QueueIntvl != 0 &&
744 	    MaxChildren > 0 && CurChildren >= MaxChildren)
745 	{
746 		char *msg = "Skipping queue run -- too many children";
747 
748 		if (verbose)
749 			message("458 %s (%d)\n", msg, CurChildren);
750 		if (LogLevel > 8)
751 			sm_syslog(LOG_INFO, NOQID,
752 				  "runqueue: %s (%d)",
753 				  msg, CurChildren);
754 		return FALSE;
755 	}
756 
757 	/*
758 	**  See if we want to go off and do other useful work.
759 	*/
760 
761 	if (forkflag)
762 	{
763 		pid_t pid;
764 
765 		(void) blocksignal(SIGCHLD);
766 		(void) setsignal(SIGCHLD, reapchild);
767 
768 		pid = dofork();
769 		if (pid == -1)
770 		{
771 			const char *msg = "Skipping queue run -- fork() failed";
772 			const char *err = errstring(errno);
773 
774 			if (verbose)
775 				message("458 %s: %s\n", msg, err);
776 			if (LogLevel > 8)
777 				sm_syslog(LOG_INFO, NOQID,
778 					  "runqueue: %s: %s",
779 					  msg, err);
780 			(void) releasesignal(SIGCHLD);
781 			return FALSE;
782 		}
783 		if (pid != 0)
784 		{
785 			/* parent -- pick up intermediate zombie */
786 			(void) blocksignal(SIGALRM);
787 			proc_list_add(pid, "Queue runner", PROC_QUEUE);
788 			(void) releasesignal(SIGALRM);
789 			(void) releasesignal(SIGCHLD);
790 			return TRUE;
791 		}
792 		/* child -- clean up signals */
793 		clrcontrol();
794 		proc_list_clear();
795 
796 		/* Add parent process as first child item */
797 		proc_list_add(getpid(), "Queue runner child process",
798 			      PROC_QUEUE_CHILD);
799 		(void) releasesignal(SIGCHLD);
800 		(void) setsignal(SIGCHLD, SIG_DFL);
801 		(void) setsignal(SIGHUP, intsig);
802 
803 	}
804 
805 	sm_setproctitle(TRUE, CurEnv, "running queue: %s",
806 			qid_printqueue(queuedir));
807 
808 	if (LogLevel > 69 || tTd(63, 99))
809 		sm_syslog(LOG_DEBUG, NOQID,
810 			  "runqueue %s, pid=%d, forkflag=%d",
811 			  qid_printqueue(queuedir), getpid(), forkflag);
812 
813 	/*
814 	**  Release any resources used by the daemon code.
815 	*/
816 
817 # if DAEMON
818 	clrdaemon();
819 # endif /* DAEMON */
820 
821 	/* force it to run expensive jobs */
822 	NoConnect = FALSE;
823 
824 	/* drop privileges */
825 	if (geteuid() == (uid_t) 0)
826 		(void) drop_privileges(FALSE);
827 
828 	/*
829 	**  Create ourselves an envelope
830 	*/
831 
832 	CurEnv = &QueueEnvelope;
833 	e = newenvelope(&QueueEnvelope, CurEnv);
834 	e->e_flags = BlankEnvelope.e_flags;
835 
836 	/* make sure we have disconnected from parent */
837 	if (forkflag)
838 	{
839 		disconnect(1, e);
840 		QuickAbort = FALSE;
841 	}
842 
843 	/*
844 	**  If we are running part of the queue, always ignore stored
845 	**  host status.
846 	*/
847 
848 	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
849 	    QueueLimitRecipient != NULL)
850 	{
851 		IgnoreHostStatus = TRUE;
852 		MinQueueAge = 0;
853 	}
854 
855 	/*
856 	**  Start making passes through the queue.
857 	**	First, read and sort the entire queue.
858 	**	Then, process the work in that order.
859 	**		But if you take too long, start over.
860 	*/
861 
862 	/* order the existing work requests */
863 	njobs = orderq(queuedir, FALSE);
864 
865 
866 	/* process them once at a time */
867 	while (WorkQ != NULL)
868 	{
869 		WORK *w = WorkQ;
870 
871 		WorkQ = WorkQ->w_next;
872 		e->e_to = NULL;
873 
874 		/*
875 		**  Ignore jobs that are too expensive for the moment.
876 		**
877 		**	Get new load average every 30 seconds.
878 		*/
879 
880 		if (current_la_time < curtime() - 30)
881 		{
882 			CurrentLA = sm_getla(e);
883 			current_la_time = curtime();
884 		}
885 		if (shouldqueue(WkRecipFact, current_la_time))
886 		{
887 			char *msg = "Aborting queue run: load average too high";
888 
889 			if (Verbose)
890 				message("%s", msg);
891 			if (LogLevel > 8)
892 				sm_syslog(LOG_INFO, NOQID,
893 					  "runqueue: %s",
894 					  msg);
895 			break;
896 		}
897 		sequenceno++;
898 		if (shouldqueue(w->w_pri, w->w_ctime))
899 		{
900 			if (Verbose)
901 				message("");
902 			if (QueueSortOrder == QSO_BYPRIORITY)
903 			{
904 				if (Verbose)
905 					message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
906 						qid_printqueue(queuedir),
907 						w->w_name + 2,
908 						sequenceno,
909 						njobs);
910 				if (LogLevel > 8)
911 					sm_syslog(LOG_INFO, NOQID,
912 						  "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
913 						  qid_printqueue(queuedir),
914 						  w->w_name + 2,
915 						  w->w_pri,
916 						  CurrentLA,
917 						  sequenceno,
918 						  njobs);
919 				break;
920 			}
921 			else if (Verbose)
922 				message("Skipping %s/%s (sequence %d of %d)",
923 					qid_printqueue(queuedir),
924 					w->w_name + 2,
925 					sequenceno, njobs);
926 		}
927 		else
928 		{
929 			pid_t pid;
930 
931 			if (Verbose)
932 			{
933 				message("");
934 				message("Running %s/%s (sequence %d of %d)",
935 					qid_printqueue(queuedir),
936 					w->w_name + 2,
937 					sequenceno, njobs);
938 			}
939 			if (tTd(63, 100))
940 				sm_syslog(LOG_DEBUG, NOQID,
941 					  "runqueue %s dowork(%s)",
942 					  qid_printqueue(queuedir),
943 					  w->w_name + 2);
944 
945 			pid = dowork(queuedir, w->w_name + 2,
946 				     ForkQueueRuns, FALSE, e);
947 			errno = 0;
948 			if (pid != 0)
949 				(void) waitfor(pid);
950 		}
951 		free(w->w_name);
952 		if (w->w_host)
953 			free(w->w_host);
954 		free((char *) w);
955 	}
956 
957 	/* exit without the usual cleanup */
958 	e->e_id = NULL;
959 	if (forkflag)
960 		finis(TRUE, ExitStat);
961 	/* NOTREACHED */
962 	return TRUE;
963 }
964 
965 /*
966 **  RUNQUEUEEVENT -- stub for use in setevent
967 */
968 
969 static void
970 runqueueevent()
971 {
972 	DoQueueRun = TRUE;
973 }
974 /*
975 **  ORDERQ -- order the work queue.
976 **
977 **	Parameters:
978 **		queuedir -- the index of the queue directory.
979 **		doall -- if set, include everything in the queue (even
980 **			the jobs that cannot be run because the load
981 **			average is too high).  Otherwise, exclude those
982 **			jobs.
983 **
984 **	Returns:
985 **		The number of request in the queue (not necessarily
986 **		the number of requests in WorkQ however).
987 **
988 **	Side Effects:
989 **		Sets WorkQ to the queue of available work, in order.
990 */
991 
992 # define NEED_P		001
993 # define NEED_T		002
994 # define NEED_R		004
995 # define NEED_S		010
996 
997 static WORK	*WorkList = NULL;
998 static int	WorkListSize = 0;
999 
1000 static int
1001 orderq(queuedir, doall)
1002 	int queuedir;
1003 	bool doall;
1004 {
1005 	register struct dirent *d;
1006 	register WORK *w;
1007 	register char *p;
1008 	DIR *f;
1009 	register int i;
1010 	int wn = -1;
1011 	int wc;
1012 	QUEUE_CHAR *check;
1013 	char qd[MAXPATHLEN];
1014 	char qf[MAXPATHLEN];
1015 
1016 	if (queuedir == NOQDIR)
1017 		(void) strlcpy(qd, ".", sizeof qd);
1018 	else
1019 		(void) snprintf(qd, sizeof qd, "%s%s",
1020 				QPaths[queuedir].qp_name,
1021 				(bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
1022 
1023 	if (tTd(41, 1))
1024 	{
1025 		dprintf("orderq:\n");
1026 
1027 		check = QueueLimitId;
1028 		while (check != NULL)
1029 		{
1030 			dprintf("\tQueueLimitId = %s\n",
1031 				check->queue_match);
1032 			check = check->queue_next;
1033 		}
1034 
1035 		check = QueueLimitSender;
1036 		while (check != NULL)
1037 		{
1038 			dprintf("\tQueueLimitSender = %s\n",
1039 				check->queue_match);
1040 			check = check->queue_next;
1041 		}
1042 
1043 		check = QueueLimitRecipient;
1044 		while (check != NULL)
1045 		{
1046 			dprintf("\tQueueLimitRecipient = %s\n",
1047 				check->queue_match);
1048 			check = check->queue_next;
1049 		}
1050 	}
1051 
1052 	/* clear out old WorkQ */
1053 	for (w = WorkQ; w != NULL; )
1054 	{
1055 		register WORK *nw = w->w_next;
1056 
1057 		WorkQ = nw;
1058 		free(w->w_name);
1059 		if (w->w_host)
1060 			free(w->w_host);
1061 		free((char *) w);
1062 		w = nw;
1063 	}
1064 
1065 	/* open the queue directory */
1066 	f = opendir(qd);
1067 	if (f == NULL)
1068 	{
1069 		syserr("orderq: cannot open \"%s\"", qid_printqueue(queuedir));
1070 		return 0;
1071 	}
1072 
1073 	/*
1074 	**  Read the work directory.
1075 	*/
1076 
1077 	while ((d = readdir(f)) != NULL)
1078 	{
1079 		FILE *cf;
1080 		int qfver = 0;
1081 		char lbuf[MAXNAME + 1];
1082 		struct stat sbuf;
1083 
1084 		if (tTd(41, 50))
1085 			dprintf("orderq: checking %s\n", d->d_name);
1086 
1087 		/* is this an interesting entry? */
1088 		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
1089 			continue;
1090 
1091 		if (strlen(d->d_name) >= MAXQFNAME)
1092 		{
1093 			if (Verbose)
1094 				printf("orderq: %s too long, %d max characters\n",
1095 					d->d_name, MAXQFNAME);
1096 			if (LogLevel > 0)
1097 				sm_syslog(LOG_ALERT, NOQID,
1098 					  "orderq: %s too long, %d max characters",
1099 					  d->d_name, MAXQFNAME);
1100 			continue;
1101 		}
1102 
1103 		check = QueueLimitId;
1104 		while (check != NULL)
1105 		{
1106 			if (strcontainedin(check->queue_match, d->d_name))
1107 				break;
1108 			else
1109 				check = check->queue_next;
1110 		}
1111 		if (QueueLimitId != NULL && check == NULL)
1112 			continue;
1113 
1114 		/* grow work list if necessary */
1115 		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
1116 		{
1117 			if (wn == MaxQueueRun && LogLevel > 0)
1118 				sm_syslog(LOG_WARNING, NOQID,
1119 					  "WorkList for %s maxed out at %d",
1120 					  qid_printqueue(queuedir),
1121 					  MaxQueueRun);
1122 			continue;
1123 		}
1124 		if (wn >= WorkListSize)
1125 		{
1126 			grow_wlist(queuedir);
1127 			if (wn >= WorkListSize)
1128 				continue;
1129 		}
1130 		w = &WorkList[wn];
1131 
1132 		(void) snprintf(qf, sizeof qf, "%s/%s", qd, d->d_name);
1133 		if (stat(qf, &sbuf) < 0)
1134 		{
1135 			if (errno != ENOENT)
1136 				sm_syslog(LOG_INFO, NOQID,
1137 					  "orderq: can't stat %s/%s",
1138 					  qid_printqueue(queuedir), d->d_name);
1139 			wn--;
1140 			continue;
1141 		}
1142 		if (!bitset(S_IFREG, sbuf.st_mode))
1143 		{
1144 			/* Yikes!  Skip it or we will hang on open! */
1145 			syserr("orderq: %s/%s is not a regular file",
1146 			       qid_printqueue(queuedir), d->d_name);
1147 			wn--;
1148 			continue;
1149 		}
1150 
1151 		/* avoid work if possible */
1152 		if (QueueSortOrder == QSO_BYFILENAME)
1153 		{
1154 			w->w_name = newstr(d->d_name);
1155 			w->w_host = NULL;
1156 			w->w_lock = w->w_tooyoung = FALSE;
1157 			w->w_pri = 0;
1158 			w->w_ctime = 0;
1159 			continue;
1160 		}
1161 
1162 		/* open control file */
1163 		cf = fopen(qf, "r");
1164 		if (cf == NULL)
1165 		{
1166 			/* this may be some random person sending hir msgs */
1167 			/* syserr("orderq: cannot open %s", cbuf); */
1168 			if (tTd(41, 2))
1169 				dprintf("orderq: cannot open %s: %s\n",
1170 					d->d_name, errstring(errno));
1171 			errno = 0;
1172 			wn--;
1173 			continue;
1174 		}
1175 		w->w_name = newstr(d->d_name);
1176 		w->w_host = NULL;
1177 		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
1178 		w->w_tooyoung = FALSE;
1179 
1180 		/* make sure jobs in creation don't clog queue */
1181 		w->w_pri = 0x7fffffff;
1182 		w->w_ctime = 0;
1183 
1184 		/* extract useful information */
1185 		i = NEED_P | NEED_T;
1186 		if (QueueLimitSender != NULL)
1187 			i |= NEED_S;
1188 		if (QueueLimitRecipient != NULL)
1189 			i |= NEED_R;
1190 		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
1191 		{
1192 			int c;
1193 			time_t age;
1194 
1195 			p = strchr(lbuf, '\n');
1196 			if (p != NULL)
1197 				*p = '\0';
1198 			else
1199 			{
1200 				/* flush rest of overly long line */
1201 				while ((c = getc(cf)) != EOF && c != '\n')
1202 					continue;
1203 			}
1204 
1205 			switch (lbuf[0])
1206 			{
1207 			  case 'V':
1208 				qfver = atoi(&lbuf[1]);
1209 				break;
1210 
1211 			  case 'P':
1212 				w->w_pri = atol(&lbuf[1]);
1213 				i &= ~NEED_P;
1214 				break;
1215 
1216 			  case 'T':
1217 				w->w_ctime = atol(&lbuf[1]);
1218 				i &= ~NEED_T;
1219 				break;
1220 
1221 			  case 'R':
1222 				if (w->w_host == NULL &&
1223 				    (p = strrchr(&lbuf[1], '@')) != NULL)
1224 				{
1225 					w->w_host = strrev(&p[1]);
1226 					makelower(w->w_host);
1227 				}
1228 				if (QueueLimitRecipient == NULL)
1229 				{
1230 					i &= ~NEED_R;
1231 					break;
1232 				}
1233 				if (qfver > 0)
1234 				{
1235 					p = strchr(&lbuf[1], ':');
1236 					if (p == NULL)
1237 						p = &lbuf[1];
1238 				}
1239 				else
1240 					p = &lbuf[1];
1241 				check = QueueLimitRecipient;
1242 				while (check != NULL)
1243 				{
1244 					if (strcontainedin(check->queue_match,
1245 							   p))
1246 						break;
1247 					else
1248 						check = check->queue_next;
1249 				}
1250 				if (check != NULL)
1251 					i &= ~NEED_R;
1252 				break;
1253 
1254 			  case 'S':
1255 				check = QueueLimitSender;
1256 				while (check != NULL)
1257 				{
1258 					if (strcontainedin(check->queue_match,
1259 							   &lbuf[1]))
1260 						break;
1261 					else
1262 						check = check->queue_next;
1263 				}
1264 				if (check != NULL)
1265 					i &= ~NEED_S;
1266 				break;
1267 
1268 			  case 'K':
1269 				age = curtime() - (time_t) atol(&lbuf[1]);
1270 				if (age >= 0 && MinQueueAge > 0 &&
1271 				    age < MinQueueAge)
1272 					w->w_tooyoung = TRUE;
1273 				break;
1274 
1275 			  case 'N':
1276 				if (atol(&lbuf[1]) == 0)
1277 					w->w_tooyoung = FALSE;
1278 				break;
1279 
1280 # if _FFR_QUEUEDELAY
1281 /*
1282 			  case 'G':
1283 				queuealg = atoi(lbuf[1]);
1284 				break;
1285 			  case 'Y':
1286 				queuedelay = (time_t) atol(&lbuf[1]);
1287 				break;
1288 */
1289 # endif /* _FFR_QUEUEDELAY */
1290 			}
1291 		}
1292 		(void) fclose(cf);
1293 
1294 		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
1295 		    bitset(NEED_R|NEED_S, i))
1296 		{
1297 			/* don't even bother sorting this job in */
1298 			if (tTd(41, 49))
1299 				dprintf("skipping %s (%x)\n", w->w_name, i);
1300 			free(w->w_name);
1301 			if (w->w_host)
1302 				free(w->w_host);
1303 			wn--;
1304 		}
1305 	}
1306 	(void) closedir(f);
1307 	wn++;
1308 
1309 	WorkQ = NULL;
1310 	if (WorkList == NULL)
1311 		return 0;
1312 	wc = min(wn, WorkListSize);
1313 	if (wc > MaxQueueRun && MaxQueueRun > 0)
1314 		wc = MaxQueueRun;
1315 
1316 	if (QueueSortOrder == QSO_BYHOST)
1317 	{
1318 		/*
1319 		**  Sort the work directory for the first time,
1320 		**  based on host name, lock status, and priority.
1321 		*/
1322 
1323 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
1324 
1325 		/*
1326 		**  If one message to host is locked, "lock" all messages
1327 		**  to that host.
1328 		*/
1329 
1330 		i = 0;
1331 		while (i < wc)
1332 		{
1333 			if (!WorkList[i].w_lock)
1334 			{
1335 				i++;
1336 				continue;
1337 			}
1338 			w = &WorkList[i];
1339 			while (++i < wc)
1340 			{
1341 				if (WorkList[i].w_host == NULL &&
1342 				    w->w_host == NULL)
1343 					WorkList[i].w_lock = TRUE;
1344 				else if (WorkList[i].w_host != NULL &&
1345 					 w->w_host != NULL &&
1346 					 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
1347 					WorkList[i].w_lock = TRUE;
1348 				else
1349 					break;
1350 			}
1351 		}
1352 
1353 		/*
1354 		**  Sort the work directory for the second time,
1355 		**  based on lock status, host name, and priority.
1356 		*/
1357 
1358 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
1359 	}
1360 	else if (QueueSortOrder == QSO_BYTIME)
1361 	{
1362 		/*
1363 		**  Simple sort based on submission time only.
1364 		*/
1365 
1366 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
1367 	}
1368 	else if (QueueSortOrder == QSO_BYFILENAME)
1369 	{
1370 		/*
1371 		**  Sort based on qf filename.
1372 		*/
1373 
1374 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
1375 	}
1376 	else
1377 	{
1378 		/*
1379 		**  Simple sort based on queue priority only.
1380 		*/
1381 
1382 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
1383 	}
1384 
1385 	/*
1386 	**  Convert the work list into canonical form.
1387 	**	Should be turning it into a list of envelopes here perhaps.
1388 	*/
1389 
1390 	for (i = wc; --i >= 0; )
1391 	{
1392 		w = (WORK *) xalloc(sizeof *w);
1393 		w->w_name = WorkList[i].w_name;
1394 		w->w_host = WorkList[i].w_host;
1395 		w->w_lock = WorkList[i].w_lock;
1396 		w->w_tooyoung = WorkList[i].w_tooyoung;
1397 		w->w_pri = WorkList[i].w_pri;
1398 		w->w_ctime = WorkList[i].w_ctime;
1399 		w->w_next = WorkQ;
1400 		WorkQ = w;
1401 	}
1402 	if (WorkList != NULL)
1403 		free(WorkList);
1404 	WorkList = NULL;
1405 	WorkListSize = 0;
1406 
1407 	if (tTd(40, 1))
1408 	{
1409 		for (w = WorkQ; w != NULL; w = w->w_next)
1410 		{
1411 			if (w->w_host != NULL)
1412 				dprintf("%22s: pri=%ld %s\n",
1413 					w->w_name, w->w_pri, w->w_host);
1414 			else
1415 				dprintf("%32s: pri=%ld\n",
1416 					w->w_name, w->w_pri);
1417 		}
1418 	}
1419 
1420 	return wn;
1421 }
1422 /*
1423 **  GROW_WLIST -- make the work list larger
1424 **
1425 **	Parameters:
1426 **		queuedir -- the index for the queue directory.
1427 **
1428 **	Returns:
1429 **		none.
1430 **
1431 **	Side Effects:
1432 **		Adds another QUEUESEGSIZE entries to WorkList if possible.
1433 **		It can fail if there isn't enough memory, so WorkListSize
1434 **		should be checked again upon return.
1435 */
1436 
1437 static void
1438 grow_wlist(queuedir)
1439 	int queuedir;
1440 {
1441 	if (tTd(41, 1))
1442 		dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
1443 	if (WorkList == NULL)
1444 	{
1445 		WorkList = (WORK *) xalloc((sizeof *WorkList) *
1446 					   (QUEUESEGSIZE + 1));
1447 		WorkListSize = QUEUESEGSIZE;
1448 	}
1449 	else
1450 	{
1451 		int newsize = WorkListSize + QUEUESEGSIZE;
1452 		WORK *newlist = (WORK *) realloc((char *)WorkList,
1453 					  (unsigned)sizeof(WORK) * (newsize + 1));
1454 
1455 		if (newlist != NULL)
1456 		{
1457 			WorkListSize = newsize;
1458 			WorkList = newlist;
1459 			if (LogLevel > 1)
1460 			{
1461 				sm_syslog(LOG_INFO, NOQID,
1462 					  "grew WorkList for %s to %d",
1463 					  qid_printqueue(queuedir),
1464 					  WorkListSize);
1465 			}
1466 		}
1467 		else if (LogLevel > 0)
1468 		{
1469 			sm_syslog(LOG_ALERT, NOQID,
1470 				  "FAILED to grow WorkList for %s to %d",
1471 				  qid_printqueue(queuedir), newsize);
1472 		}
1473 	}
1474 	if (tTd(41, 1))
1475 		dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
1476 }
1477 /*
1478 **  WORKCMPF0 -- simple priority-only compare function.
1479 **
1480 **	Parameters:
1481 **		a -- the first argument.
1482 **		b -- the second argument.
1483 **
1484 **	Returns:
1485 **		-1 if a < b
1486 **		 0 if a == b
1487 **		+1 if a > b
1488 **
1489 **	Side Effects:
1490 **		none.
1491 */
1492 
1493 static int
1494 workcmpf0(a, b)
1495 	register WORK *a;
1496 	register WORK *b;
1497 {
1498 	long pa = a->w_pri;
1499 	long pb = b->w_pri;
1500 
1501 	if (pa == pb)
1502 		return 0;
1503 	else if (pa > pb)
1504 		return 1;
1505 	else
1506 		return -1;
1507 }
1508 /*
1509 **  WORKCMPF1 -- first compare function for ordering work based on host name.
1510 **
1511 **	Sorts on host name, lock status, and priority in that order.
1512 **
1513 **	Parameters:
1514 **		a -- the first argument.
1515 **		b -- the second argument.
1516 **
1517 **	Returns:
1518 **		<0 if a < b
1519 **		 0 if a == b
1520 **		>0 if a > b
1521 **
1522 **	Side Effects:
1523 **		none.
1524 */
1525 
1526 static int
1527 workcmpf1(a, b)
1528 	register WORK *a;
1529 	register WORK *b;
1530 {
1531 	int i;
1532 
1533 	/* host name */
1534 	if (a->w_host != NULL && b->w_host == NULL)
1535 		return 1;
1536 	else if (a->w_host == NULL && b->w_host != NULL)
1537 		return -1;
1538 	if (a->w_host != NULL && b->w_host != NULL &&
1539 	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1540 		return i;
1541 
1542 	/* lock status */
1543 	if (a->w_lock != b->w_lock)
1544 		return b->w_lock - a->w_lock;
1545 
1546 	/* job priority */
1547 	return a->w_pri - b->w_pri;
1548 }
1549 /*
1550 **  WORKCMPF2 -- second compare function for ordering work based on host name.
1551 **
1552 **	Sorts on lock status, host name, and priority in that order.
1553 **
1554 **	Parameters:
1555 **		a -- the first argument.
1556 **		b -- the second argument.
1557 **
1558 **	Returns:
1559 **		<0 if a < b
1560 **		 0 if a == b
1561 **		>0 if a > b
1562 **
1563 **	Side Effects:
1564 **		none.
1565 */
1566 
1567 static int
1568 workcmpf2(a, b)
1569 	register WORK *a;
1570 	register WORK *b;
1571 {
1572 	int i;
1573 
1574 	/* lock status */
1575 	if (a->w_lock != b->w_lock)
1576 		return a->w_lock - b->w_lock;
1577 
1578 	/* host name */
1579 	if (a->w_host != NULL && b->w_host == NULL)
1580 		return 1;
1581 	else if (a->w_host == NULL && b->w_host != NULL)
1582 		return -1;
1583 	if (a->w_host != NULL && b->w_host != NULL &&
1584 	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1585 		return i;
1586 
1587 	/* job priority */
1588 	return a->w_pri - b->w_pri;
1589 }
1590 /*
1591 **  WORKCMPF3 -- simple submission-time-only compare function.
1592 **
1593 **	Parameters:
1594 **		a -- the first argument.
1595 **		b -- the second argument.
1596 **
1597 **	Returns:
1598 **		-1 if a < b
1599 **		 0 if a == b
1600 **		+1 if a > b
1601 **
1602 **	Side Effects:
1603 **		none.
1604 */
1605 
1606 static int
1607 workcmpf3(a, b)
1608 	register WORK *a;
1609 	register WORK *b;
1610 {
1611 	if (a->w_ctime > b->w_ctime)
1612 		return 1;
1613 	else if (a->w_ctime < b->w_ctime)
1614 		return -1;
1615 	else
1616 		return 0;
1617 }
1618 /*
1619 **  WORKCMPF4 -- compare based on file name
1620 **
1621 **	Parameters:
1622 **		a -- the first argument.
1623 **		b -- the second argument.
1624 **
1625 **	Returns:
1626 **		-1 if a < b
1627 **		 0 if a == b
1628 **		+1 if a > b
1629 **
1630 **	Side Effects:
1631 **		none.
1632 */
1633 
1634 static int
1635 workcmpf4(a, b)
1636 	register WORK *a;
1637 	register WORK *b;
1638 {
1639 	return strcmp(a->w_name, b->w_name);
1640 }
1641 /*
1642 **  STRREV -- reverse string
1643 **
1644 **	Returns a pointer to a new string that is the reverse of
1645 **	the string pointed to by fwd.  The space for the new
1646 **	string is obtained using xalloc().
1647 **
1648 **	Parameters:
1649 **		fwd -- the string to reverse.
1650 **
1651 **	Returns:
1652 **		the reversed string.
1653 */
1654 
1655 static char *
1656 strrev(fwd)
1657 	char *fwd;
1658 {
1659 	char *rev = NULL;
1660 	int len, cnt;
1661 
1662 	len = strlen(fwd);
1663 	rev = xalloc(len + 1);
1664 	for (cnt = 0; cnt < len; ++cnt)
1665 		rev[cnt] = fwd[len - cnt - 1];
1666 	rev[len] = '\0';
1667 	return rev;
1668 }
1669 /*
1670 **  DOWORK -- do a work request.
1671 **
1672 **	Parameters:
1673 **		queuedir -- the index of the queue directory for the job.
1674 **		id -- the ID of the job to run.
1675 **		forkflag -- if set, run this in background.
1676 **		requeueflag -- if set, reinstantiate the queue quickly.
1677 **			This is used when expanding aliases in the queue.
1678 **			If forkflag is also set, it doesn't wait for the
1679 **			child.
1680 **		e - the envelope in which to run it.
1681 **
1682 **	Returns:
1683 **		process id of process that is running the queue job.
1684 **
1685 **	Side Effects:
1686 **		The work request is satisfied if possible.
1687 */
1688 
1689 pid_t
1690 dowork(queuedir, id, forkflag, requeueflag, e)
1691 	int queuedir;
1692 	char *id;
1693 	bool forkflag;
1694 	bool requeueflag;
1695 	register ENVELOPE *e;
1696 {
1697 	register pid_t pid;
1698 
1699 	if (tTd(40, 1))
1700 		dprintf("dowork(%s/%s)\n", qid_printqueue(queuedir), id);
1701 
1702 	/*
1703 	**  Fork for work.
1704 	*/
1705 
1706 	if (forkflag)
1707 	{
1708 		/*
1709 		**  Since the delivery may happen in a child and the
1710 		**  parent does not wait, the parent may close the
1711 		**  maps thereby removing any shared memory used by
1712 		**  the map.  Therefore, close the maps now so the
1713 		**  child will dynamically open them if necessary.
1714 		*/
1715 
1716 		closemaps();
1717 
1718 		pid = fork();
1719 		if (pid < 0)
1720 		{
1721 			syserr("dowork: cannot fork");
1722 			return 0;
1723 		}
1724 		else if (pid > 0)
1725 		{
1726 			/* parent -- clean out connection cache */
1727 			mci_flush(FALSE, NULL);
1728 		}
1729 		else
1730 		{
1731 			/* child -- error messages to the transcript */
1732 			QuickAbort = OnlyOneError = FALSE;
1733 		}
1734 	}
1735 	else
1736 	{
1737 		pid = 0;
1738 	}
1739 
1740 	if (pid == 0)
1741 	{
1742 		/*
1743 		**  CHILD
1744 		**	Lock the control file to avoid duplicate deliveries.
1745 		**		Then run the file as though we had just read it.
1746 		**	We save an idea of the temporary name so we
1747 		**		can recover on interrupt.
1748 		*/
1749 
1750 		/* set basic modes, etc. */
1751 		(void) alarm(0);
1752 		clearstats();
1753 		clearenvelope(e, FALSE);
1754 		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1755 		set_delivery_mode(SM_DELIVER, e);
1756 		e->e_errormode = EM_MAIL;
1757 		e->e_id = id;
1758 		e->e_queuedir = queuedir;
1759 		GrabTo = UseErrorsTo = FALSE;
1760 		ExitStat = EX_OK;
1761 		if (forkflag)
1762 		{
1763 			disconnect(1, e);
1764 			OpMode = MD_QUEUERUN;
1765 		}
1766 		sm_setproctitle(TRUE, e, "%s: from queue", qid_printname(e));
1767 		if (LogLevel > 76)
1768 			sm_syslog(LOG_DEBUG, e->e_id,
1769 				  "dowork, pid=%d",
1770 				  getpid());
1771 
1772 		/* don't use the headers from sendmail.cf... */
1773 		e->e_header = NULL;
1774 
1775 		/* read the queue control file -- return if locked */
1776 		if (!readqf(e))
1777 		{
1778 			if (tTd(40, 4) && e->e_id != NULL)
1779 				dprintf("readqf(%s) failed\n",
1780 					qid_printname(e));
1781 			e->e_id = NULL;
1782 			if (forkflag)
1783 				finis(FALSE, EX_OK);
1784 			else
1785 				return 0;
1786 		}
1787 
1788 		e->e_flags |= EF_INQUEUE;
1789 		eatheader(e, requeueflag);
1790 
1791 		if (requeueflag)
1792 			queueup(e, FALSE);
1793 
1794 		/* do the delivery */
1795 		sendall(e, SM_DELIVER);
1796 
1797 		/* finish up and exit */
1798 		if (forkflag)
1799 			finis(TRUE, ExitStat);
1800 		else
1801 			dropenvelope(e, TRUE);
1802 	}
1803 	e->e_id = NULL;
1804 	return pid;
1805 }
1806 /*
1807 **  READQF -- read queue file and set up environment.
1808 **
1809 **	Parameters:
1810 **		e -- the envelope of the job to run.
1811 **
1812 **	Returns:
1813 **		TRUE if it successfully read the queue file.
1814 **		FALSE otherwise.
1815 **
1816 **	Side Effects:
1817 **		The queue file is returned locked.
1818 */
1819 
1820 static bool
1821 readqf(e)
1822 	register ENVELOPE *e;
1823 {
1824 	register FILE *qfp;
1825 	ADDRESS *ctladdr;
1826 	struct stat st;
1827 	char *bp;
1828 	int qfver = 0;
1829 	long hdrsize = 0;
1830 	register char *p;
1831 	char *orcpt = NULL;
1832 	bool nomore = FALSE;
1833 	MODE_T qsafe;
1834 	char qf[MAXPATHLEN];
1835 	char buf[MAXLINE];
1836 
1837 	/*
1838 	**  Read and process the file.
1839 	*/
1840 
1841 	(void) strlcpy(qf, queuename(e, 'q'), sizeof qf);
1842 	qfp = fopen(qf, "r+");
1843 	if (qfp == NULL)
1844 	{
1845 		int save_errno = errno;
1846 
1847 		if (tTd(40, 8))
1848 			dprintf("readqf(%s): fopen failure (%s)\n",
1849 				qf, errstring(errno));
1850 		errno = save_errno;
1851 		if (errno != ENOENT
1852 		    )
1853 			syserr("readqf: no control file %s", qf);
1854 		return FALSE;
1855 	}
1856 
1857 	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1858 	{
1859 		/* being processed by another queuer */
1860 		if (Verbose)
1861 			printf("%s: locked\n", e->e_id);
1862 		if (tTd(40, 8))
1863 			dprintf("%s: locked\n", e->e_id);
1864 		if (LogLevel > 19)
1865 			sm_syslog(LOG_DEBUG, e->e_id, "locked");
1866 		(void) fclose(qfp);
1867 		return FALSE;
1868 	}
1869 
1870 	/*
1871 	**  Check the queue file for plausibility to avoid attacks.
1872 	*/
1873 
1874 	if (fstat(fileno(qfp), &st) < 0)
1875 	{
1876 		/* must have been being processed by someone else */
1877 		if (tTd(40, 8))
1878 			dprintf("readqf(%s): fstat failure (%s)\n",
1879 				qf, errstring(errno));
1880 		(void) fclose(qfp);
1881 		return FALSE;
1882 	}
1883 
1884 	qsafe = S_IWOTH|S_IWGRP;
1885 #if _FFR_QUEUE_FILE_MODE
1886 	if (bitset(S_IWGRP, QueueFileMode))
1887 		qsafe &= ~S_IWGRP;
1888 #endif /* _FFR_QUEUE_FILE_MODE */
1889 
1890 	if ((st.st_uid != geteuid() &&
1891 	     st.st_uid != TrustedUid &&
1892 	     geteuid() != RealUid) ||
1893 	    bitset(qsafe, st.st_mode))
1894 	{
1895 		if (LogLevel > 0)
1896 		{
1897 			sm_syslog(LOG_ALERT, e->e_id,
1898 				  "bogus queue file, uid=%d, mode=%o",
1899 				  st.st_uid, st.st_mode);
1900 		}
1901 		if (tTd(40, 8))
1902 			dprintf("readqf(%s): bogus file\n", qf);
1903 		loseqfile(e, "bogus file uid in mqueue");
1904 		(void) fclose(qfp);
1905 		return FALSE;
1906 	}
1907 
1908 	if (st.st_size == 0)
1909 	{
1910 		/* must be a bogus file -- if also old, just remove it */
1911 		if (st.st_ctime + 10 * 60 < curtime())
1912 		{
1913 			(void) xunlink(queuename(e, 'd'));
1914 			(void) xunlink(queuename(e, 'q'));
1915 		}
1916 		(void) fclose(qfp);
1917 		return FALSE;
1918 	}
1919 
1920 	if (st.st_nlink == 0)
1921 	{
1922 		/*
1923 		**  Race condition -- we got a file just as it was being
1924 		**  unlinked.  Just assume it is zero length.
1925 		*/
1926 
1927 		(void) fclose(qfp);
1928 		return FALSE;
1929 	}
1930 
1931 	/* good file -- save this lock */
1932 	e->e_lockfp = qfp;
1933 
1934 	/* do basic system initialization */
1935 	initsys(e);
1936 	define('i', e->e_id, e);
1937 
1938 	LineNumber = 0;
1939 	e->e_flags |= EF_GLOBALERRS;
1940 	OpMode = MD_QUEUERUN;
1941 	ctladdr = NULL;
1942 	e->e_dfino = -1;
1943 	e->e_msgsize = -1;
1944 # if _FFR_QUEUEDELAY
1945 	e->e_queuealg = QD_LINEAR;
1946 	e->e_queuedelay = (time_t) 0;
1947 # endif /* _FFR_QUEUEDELAY */
1948 	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1949 	{
1950 		u_long qflags;
1951 		ADDRESS *q;
1952 		int mid;
1953 		auto char *ep;
1954 
1955 		if (tTd(40, 4))
1956 			dprintf("+++++ %s\n", bp);
1957 		if (nomore)
1958 		{
1959 			/* hack attack */
1960 			syserr("SECURITY ALERT: extra data in qf: %s", bp);
1961 			(void) fclose(qfp);
1962 			loseqfile(e, "bogus queue line");
1963 			return FALSE;
1964 		}
1965 		switch (bp[0])
1966 		{
1967 		  case 'V':		/* queue file version number */
1968 			qfver = atoi(&bp[1]);
1969 			if (qfver <= QF_VERSION)
1970 				break;
1971 			syserr("Version number in qf (%d) greater than max (%d)",
1972 				qfver, QF_VERSION);
1973 			(void) fclose(qfp);
1974 			loseqfile(e, "unsupported qf file version");
1975 			return FALSE;
1976 
1977 		  case 'C':		/* specify controlling user */
1978 			ctladdr = setctluser(&bp[1], qfver);
1979 			break;
1980 
1981 		  case 'Q':		/* original recipient */
1982 			orcpt = newstr(&bp[1]);
1983 			break;
1984 
1985 		  case 'R':		/* specify recipient */
1986 			p = bp;
1987 			qflags = 0;
1988 			if (qfver >= 1)
1989 			{
1990 				/* get flag bits */
1991 				while (*++p != '\0' && *p != ':')
1992 				{
1993 					switch (*p)
1994 					{
1995 					  case 'N':
1996 						qflags |= QHASNOTIFY;
1997 						break;
1998 
1999 					  case 'S':
2000 						qflags |= QPINGONSUCCESS;
2001 						break;
2002 
2003 					  case 'F':
2004 						qflags |= QPINGONFAILURE;
2005 						break;
2006 
2007 					  case 'D':
2008 						qflags |= QPINGONDELAY;
2009 						break;
2010 
2011 					  case 'P':
2012 						qflags |= QPRIMARY;
2013 						break;
2014 					}
2015 				}
2016 			}
2017 			else
2018 				qflags |= QPRIMARY;
2019 			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
2020 			if (q != NULL)
2021 			{
2022 				q->q_alias = ctladdr;
2023 				if (qfver >= 1)
2024 					q->q_flags &= ~Q_PINGFLAGS;
2025 				q->q_flags |= qflags;
2026 				q->q_orcpt = orcpt;
2027 				(void) recipient(q, &e->e_sendqueue, 0, e);
2028 			}
2029 			orcpt = NULL;
2030 			break;
2031 
2032 		  case 'E':		/* specify error recipient */
2033 			/* no longer used */
2034 			break;
2035 
2036 		  case 'H':		/* header */
2037 			(void) chompheader(&bp[1], 0, NULL, e);
2038 			hdrsize += strlen(&bp[1]);
2039 			break;
2040 
2041 		  case 'L':		/* Solaris Content-Length: */
2042 		  case 'M':		/* message */
2043 			/* ignore this; we want a new message next time */
2044 			break;
2045 
2046 		  case 'S':		/* sender */
2047 			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
2048 			break;
2049 
2050 		  case 'B':		/* body type */
2051 			e->e_bodytype = newstr(&bp[1]);
2052 			break;
2053 
2054 # if _FFR_SAVE_CHARSET
2055 		  case 'X':		/* character set */
2056 			e->e_charset = newstr(&bp[1]);
2057 			break;
2058 # endif /* _FFR_SAVE_CHARSET */
2059 
2060 		  case 'D':		/* data file name */
2061 			/* obsolete -- ignore */
2062 			break;
2063 
2064 		  case 'T':		/* init time */
2065 			e->e_ctime = atol(&bp[1]);
2066 			break;
2067 
2068 		  case 'I':		/* data file's inode number */
2069 			/* regenerated below */
2070 			break;
2071 
2072 		  case 'K':	/* time of last delivery attempt */
2073 			e->e_dtime = atol(&buf[1]);
2074 			break;
2075 
2076 # if _FFR_QUEUEDELAY
2077 		  case 'G':	/* queue delay algorithm */
2078 			e->e_queuealg = atoi(&buf[1]);
2079 			break;
2080 		  case 'Y':	/* current delay */
2081 			e->e_queuedelay = (time_t) atol(&buf[1]);
2082 			break;
2083 # endif /* _FFR_QUEUEDELAY */
2084 
2085 		  case 'N':		/* number of delivery attempts */
2086 			e->e_ntries = atoi(&buf[1]);
2087 
2088 			/* if this has been tried recently, let it be */
2089 			if (e->e_ntries > 0 && e->e_dtime <= curtime() &&
2090 			    curtime() < e->e_dtime + queuedelay(e))
2091 			{
2092 				char *howlong;
2093 
2094 				howlong = pintvl(curtime() - e->e_dtime, TRUE);
2095 				if (Verbose)
2096 					printf("%s: too young (%s)\n",
2097 					       e->e_id, howlong);
2098 				if (tTd(40, 8))
2099 					dprintf("%s: too young (%s)\n",
2100 						e->e_id, howlong);
2101 				if (LogLevel > 19)
2102 					sm_syslog(LOG_DEBUG, e->e_id,
2103 						  "too young (%s)",
2104 						  howlong);
2105 				e->e_id = NULL;
2106 				unlockqueue(e);
2107 				return FALSE;
2108 			}
2109 			define(macid("{ntries}", NULL), newstr(&buf[1]), e);
2110 
2111 # if NAMED_BIND
2112 			/* adjust BIND parameters immediately */
2113 			if (e->e_ntries == 0)
2114 			{
2115 				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2116 				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2117 			}
2118 			else
2119 			{
2120 				_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
2121 				_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
2122 			}
2123 # endif /* NAMED_BIND */
2124 			break;
2125 
2126 		  case 'P':		/* message priority */
2127 			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
2128 			break;
2129 
2130 		  case 'F':		/* flag bits */
2131 			if (strncmp(bp, "From ", 5) == 0)
2132 			{
2133 				/* we are being spoofed! */
2134 				syserr("SECURITY ALERT: bogus qf line %s", bp);
2135 				(void) fclose(qfp);
2136 				loseqfile(e, "bogus queue line");
2137 				return FALSE;
2138 			}
2139 			for (p = &bp[1]; *p != '\0'; p++)
2140 			{
2141 				switch (*p)
2142 				{
2143 				  case 'w':	/* warning sent */
2144 					e->e_flags |= EF_WARNING;
2145 					break;
2146 
2147 				  case 'r':	/* response */
2148 					e->e_flags |= EF_RESPONSE;
2149 					break;
2150 
2151 				  case '8':	/* has 8 bit data */
2152 					e->e_flags |= EF_HAS8BIT;
2153 					break;
2154 
2155 				  case 'b':	/* delete Bcc: header */
2156 					e->e_flags |= EF_DELETE_BCC;
2157 					break;
2158 
2159 				  case 'd':	/* envelope has DSN RET= */
2160 					e->e_flags |= EF_RET_PARAM;
2161 					break;
2162 
2163 				  case 'n':	/* don't return body */
2164 					e->e_flags |= EF_NO_BODY_RETN;
2165 					break;
2166 				}
2167 			}
2168 			break;
2169 
2170 		  case 'Z':		/* original envelope id from ESMTP */
2171 			e->e_envid = newstr(&bp[1]);
2172 			define(macid("{dsn_envid}", NULL), newstr(&bp[1]), e);
2173 			break;
2174 
2175 		  case 'A':		/* AUTH= parameter */
2176 			e->e_auth_param = newstr(&bp[1]);
2177 			break;
2178 
2179 		  case '$':		/* define macro */
2180 			{
2181 				char *p;
2182 
2183 				mid = macid(&bp[1], &ep);
2184 				p = newstr(ep);
2185 				define(mid, p, e);
2186 
2187 				/*
2188 				**  HACK ALERT: Unfortunately, 8.10 and
2189 				**  8.11 reused the ${if_addr} and
2190 				**  ${if_family} macros for both the incoming
2191 				**  interface address/family (getrequests())
2192 				**  and the outgoing interface address/family
2193 				**  (makeconnection()).  In order for D_BINDIF
2194 				**  to work properly, have to preserve the
2195 				**  incoming information in the queue file for
2196 				**  later delivery attempts.  The original
2197 				**  information is stored in the envelope
2198 				**  in readqf() so it can be stored in
2199 				**  queueup_macros().  This should be fixed
2200 				**  in 8.12.
2201 				*/
2202 
2203 				if (strcmp(macname(mid), "if_addr") == 0)
2204 					e->e_if_macros[EIF_ADDR] = p;
2205 			}
2206 			break;
2207 
2208 		  case '.':		/* terminate file */
2209 			nomore = TRUE;
2210 			break;
2211 
2212 		  default:
2213 			syserr("readqf: %s: line %d: bad line \"%s\"",
2214 				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
2215 			(void) fclose(qfp);
2216 			loseqfile(e, "unrecognized line");
2217 			return FALSE;
2218 		}
2219 
2220 		if (bp != buf)
2221 			free(bp);
2222 	}
2223 
2224 	/*
2225 	**  If we haven't read any lines, this queue file is empty.
2226 	**  Arrange to remove it without referencing any null pointers.
2227 	*/
2228 
2229 	if (LineNumber == 0)
2230 	{
2231 		errno = 0;
2232 		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
2233 		return TRUE;
2234 	}
2235 
2236 	/* possibly set ${dsn_ret} macro */
2237 	if (bitset(EF_RET_PARAM, e->e_flags))
2238 	{
2239 		if (bitset(EF_NO_BODY_RETN, e->e_flags))
2240 			define(macid("{dsn_ret}", NULL), "hdrs", e);
2241 		else
2242 			define(macid("{dsn_ret}", NULL), "full", e);
2243 	}
2244 
2245 	/*
2246 	**  Arrange to read the data file.
2247 	*/
2248 
2249 	p = queuename(e, 'd');
2250 	e->e_dfp = fopen(p, "r");
2251 	if (e->e_dfp == NULL)
2252 	{
2253 		syserr("readqf: cannot open %s", p);
2254 	}
2255 	else
2256 	{
2257 		e->e_flags |= EF_HAS_DF;
2258 		if (fstat(fileno(e->e_dfp), &st) >= 0)
2259 		{
2260 			e->e_msgsize = st.st_size + hdrsize;
2261 			e->e_dfdev = st.st_dev;
2262 			e->e_dfino = st.st_ino;
2263 		}
2264 	}
2265 
2266 	return TRUE;
2267 }
2268 /*
2269 **  PRTSTR -- print a string, "unprintable" characters are shown as \oct
2270 **
2271 **	Parameters:
2272 **		s -- string to print
2273 **		ml -- maximum length of output
2274 **
2275 **	Returns:
2276 **		none.
2277 **
2278 **	Side Effects:
2279 **		Prints a string on stdout.
2280 */
2281 
2282 static void
2283 prtstr(s, ml)
2284 	char *s;
2285 	int ml;
2286 {
2287 	char c;
2288 
2289 	if (s == NULL)
2290 		return;
2291 	while (ml-- > 0 && ((c = *s++) != '\0'))
2292 	{
2293 		if (c == '\\')
2294 		{
2295 			if (ml-- > 0)
2296 			{
2297 				putchar(c);
2298 				putchar(c);
2299 			}
2300 		}
2301 		else if (isascii(c) && isprint(c))
2302 			putchar(c);
2303 		else
2304 		{
2305 			if ((ml -= 3) > 0)
2306 				printf("\\%03o", c);
2307 		}
2308 	}
2309 }
2310 /*
2311 **  PRINTQUEUE -- print out a representation of the mail queue
2312 **
2313 **	Parameters:
2314 **		none.
2315 **
2316 **	Returns:
2317 **		none.
2318 **
2319 **	Side Effects:
2320 **		Prints a listing of the mail queue on the standard output.
2321 */
2322 
2323 void
2324 printqueue()
2325 {
2326 	int i, nrequests = 0;
2327 
2328 	for (i = 0; i < NumQueues; i++)
2329 		nrequests += print_single_queue(i);
2330 	if (NumQueues > 1)
2331 		printf("\t\tTotal Requests: %d\n", nrequests);
2332 }
2333 /*
2334 **  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
2335 **
2336 **	Parameters:
2337 **		queuedir -- queue directory
2338 **
2339 **	Returns:
2340 **		none.
2341 **
2342 **	Side Effects:
2343 **		Prints a listing of the mail queue on the standard output.
2344 */
2345 
2346 static int
2347 print_single_queue(queuedir)
2348 	int queuedir;
2349 {
2350 	register WORK *w;
2351 	FILE *f;
2352 	int nrequests;
2353 	char qd[MAXPATHLEN];
2354 	char qddf[MAXPATHLEN];
2355 	char buf[MAXLINE];
2356 
2357 	if (queuedir == NOQDIR)
2358 	{
2359 		(void) strlcpy(qd, ".", sizeof qd);
2360 		(void) strlcpy(qddf, ".", sizeof qddf);
2361 	}
2362 	else
2363 	{
2364 		(void) snprintf(qd, sizeof qd, "%s%s",
2365 				QPaths[queuedir].qp_name,
2366 				(bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
2367 		(void) snprintf(qddf, sizeof qddf, "%s%s",
2368 				QPaths[queuedir].qp_name,
2369 				(bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
2370 	}
2371 
2372 	/*
2373 	**  Check for permission to print the queue
2374 	*/
2375 
2376 	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
2377 	{
2378 		struct stat st;
2379 # ifdef NGROUPS_MAX
2380 		int n;
2381 		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
2382 # endif /* NGROUPS_MAX */
2383 
2384 		if (stat(qd, &st) < 0)
2385 		{
2386 			syserr("Cannot stat %s", qid_printqueue(queuedir));
2387 			return 0;
2388 		}
2389 # ifdef NGROUPS_MAX
2390 		n = NGROUPS_MAX;
2391 		while (--n >= 0)
2392 		{
2393 			if (InitialGidSet[n] == st.st_gid)
2394 				break;
2395 		}
2396 		if (n < 0 && RealGid != st.st_gid)
2397 # else /* NGROUPS_MAX */
2398 		if (RealGid != st.st_gid)
2399 # endif /* NGROUPS_MAX */
2400 		{
2401 			usrerr("510 You are not permitted to see the queue");
2402 			setstat(EX_NOPERM);
2403 			return 0;
2404 		}
2405 	}
2406 
2407 	/*
2408 	**  Read and order the queue.
2409 	*/
2410 
2411 	nrequests = orderq(queuedir, TRUE);
2412 
2413 	/*
2414 	**  Print the work list that we have read.
2415 	*/
2416 
2417 	/* first see if there is anything */
2418 	if (nrequests <= 0)
2419 	{
2420 		printf("%s is empty\n", qid_printqueue(queuedir));
2421 		return 0;
2422 	}
2423 
2424 	CurrentLA = sm_getla(NULL);	/* get load average */
2425 
2426 	printf("\t\t%s (%d request%s", qid_printqueue(queuedir), nrequests,
2427 	       nrequests == 1 ? "" : "s");
2428 	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
2429 		printf(", only %d printed", MaxQueueRun);
2430 	if (Verbose)
2431 		printf(")\n----Q-ID---- --Size-- -Priority- ---Q-Time--- ---------Sender/Recipient--------\n");
2432 	else
2433 		printf(")\n----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
2434 	for (w = WorkQ; w != NULL; w = w->w_next)
2435 	{
2436 		struct stat st;
2437 		auto time_t submittime = 0;
2438 		long dfsize;
2439 		int flags = 0;
2440 		int qfver;
2441 		char statmsg[MAXLINE];
2442 		char bodytype[MAXNAME + 1];
2443 		char qf[MAXPATHLEN];
2444 
2445 		printf("%12s", w->w_name + 2);
2446 		(void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name);
2447 		f = fopen(qf, "r");
2448 		if (f == NULL)
2449 		{
2450 			printf(" (job completed)\n");
2451 			errno = 0;
2452 			continue;
2453 		}
2454 		w->w_name[0] = 'd';
2455 		(void) snprintf(qf, sizeof qf, "%s/%s", qddf, w->w_name);
2456 		if (stat(qf, &st) >= 0)
2457 			dfsize = st.st_size;
2458 		else
2459 			dfsize = -1;
2460 		if (w->w_lock)
2461 			printf("*");
2462 		else if (w->w_tooyoung)
2463 			printf("-");
2464 		else if (shouldqueue(w->w_pri, w->w_ctime))
2465 			printf("X");
2466 		else
2467 			printf(" ");
2468 		errno = 0;
2469 
2470 		statmsg[0] = bodytype[0] = '\0';
2471 		qfver = 0;
2472 		while (fgets(buf, sizeof buf, f) != NULL)
2473 		{
2474 			register int i;
2475 			register char *p;
2476 
2477 			fixcrlf(buf, TRUE);
2478 			switch (buf[0])
2479 			{
2480 			  case 'V':	/* queue file version */
2481 				qfver = atoi(&buf[1]);
2482 				break;
2483 
2484 			  case 'M':	/* error message */
2485 				if ((i = strlen(&buf[1])) >= sizeof statmsg)
2486 					i = sizeof statmsg - 1;
2487 				memmove(statmsg, &buf[1], i);
2488 				statmsg[i] = '\0';
2489 				break;
2490 
2491 			  case 'B':	/* body type */
2492 				if ((i = strlen(&buf[1])) >= sizeof bodytype)
2493 					i = sizeof bodytype - 1;
2494 				memmove(bodytype, &buf[1], i);
2495 				bodytype[i] = '\0';
2496 				break;
2497 
2498 			  case 'S':	/* sender name */
2499 				if (Verbose)
2500 				{
2501 					printf("%8ld %10ld%c%.12s ",
2502 					       dfsize,
2503 					       w->w_pri,
2504 					       bitset(EF_WARNING, flags) ? '+' : ' ',
2505 					       ctime(&submittime) + 4);
2506 					prtstr(&buf[1], 78);
2507 				}
2508 				else
2509 				{
2510 					printf("%8ld %.16s ", dfsize,
2511 					    ctime(&submittime));
2512 					prtstr(&buf[1], 40);
2513 				}
2514 				if (statmsg[0] != '\0' || bodytype[0] != '\0')
2515 				{
2516 					printf("\n    %10.10s", bodytype);
2517 					if (statmsg[0] != '\0')
2518 						printf("   (%.*s)",
2519 						       Verbose ? 100 : 60,
2520 						       statmsg);
2521 				}
2522 				break;
2523 
2524 			  case 'C':	/* controlling user */
2525 				if (Verbose)
2526 					printf("\n\t\t\t\t      (---%.74s---)",
2527 					       &buf[1]);
2528 				break;
2529 
2530 			  case 'R':	/* recipient name */
2531 				p = &buf[1];
2532 				if (qfver >= 1)
2533 				{
2534 					p = strchr(p, ':');
2535 					if (p == NULL)
2536 						break;
2537 					p++;
2538 				}
2539 				if (Verbose)
2540 				{
2541 					printf("\n\t\t\t\t\t      ");
2542 					prtstr(p, 73);
2543 				}
2544 				else
2545 				{
2546 					printf("\n\t\t\t\t       ");
2547 					prtstr(p, 40);
2548 				}
2549 				break;
2550 
2551 			  case 'T':	/* creation time */
2552 				submittime = atol(&buf[1]);
2553 				break;
2554 
2555 			  case 'F':	/* flag bits */
2556 				for (p = &buf[1]; *p != '\0'; p++)
2557 				{
2558 					switch (*p)
2559 					{
2560 					  case 'w':
2561 						flags |= EF_WARNING;
2562 						break;
2563 					}
2564 				}
2565 			}
2566 		}
2567 		if (submittime == (time_t) 0)
2568 			printf(" (no control file)");
2569 		printf("\n");
2570 		(void) fclose(f);
2571 	}
2572 	return nrequests;
2573 }
2574 /*
2575 **  QUEUENAME -- build a file name in the queue directory for this envelope.
2576 **
2577 **	Parameters:
2578 **		e -- envelope to build it in/from.
2579 **		type -- the file type, used as the first character
2580 **			of the file name.
2581 **
2582 **	Returns:
2583 **		a pointer to the queue name (in a static buffer).
2584 **
2585 **	Side Effects:
2586 **		If no id code is already assigned, queuename() will
2587 **		assign an id code with assign_queueid().  If no queue
2588 **		directory is assigned, one will be set with setnewqueue().
2589 */
2590 
2591 char *
2592 queuename(e, type)
2593 	register ENVELOPE *e;
2594 	int type;
2595 {
2596 	char *sub = "";
2597 	static char buf[MAXPATHLEN];
2598 
2599 	/* Assign an ID if needed */
2600 	if (e->e_id == NULL)
2601 		assign_queueid(e);
2602 
2603 	/* Assign a queue directory if needed */
2604 	if (e->e_queuedir == NOQDIR)
2605 		setnewqueue(e);
2606 
2607 	if (e->e_queuedir == NOQDIR)
2608 		(void) snprintf(buf, sizeof buf, "%cf%s",
2609 				type, e->e_id);
2610 	else
2611 	{
2612 		switch (type)
2613 		{
2614 		  case 'd':
2615 			if (bitset(QP_SUBDF, QPaths[e->e_queuedir].qp_subdirs))
2616 				sub = "/df";
2617 			break;
2618 
2619 		  case 'T':
2620 		  case 't':
2621 		  case 'Q':
2622 		  case 'q':
2623 			if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs))
2624 				sub = "/qf";
2625 			break;
2626 
2627 		  case 'x':
2628 			if (bitset(QP_SUBXF, QPaths[e->e_queuedir].qp_subdirs))
2629 				sub = "/xf";
2630 			break;
2631 		}
2632 
2633 		(void) snprintf(buf, sizeof buf, "%s%s/%cf%s",
2634 				QPaths[e->e_queuedir].qp_name,
2635 				sub, type, e->e_id);
2636 	}
2637 
2638 	if (tTd(7, 2))
2639 		dprintf("queuename: %s\n", buf);
2640 	return buf;
2641 }
2642 /*
2643 **  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
2644 **
2645 **	Assigns an id code if one does not already exist.
2646 **	This code assumes that nothing will remain in the queue for
2647 **	longer than 60 years.  It is critical that files with the given
2648 **	name not already exist in the queue.
2649 **	Also initializes e_queuedir to NOQDIR.
2650 **
2651 **	Parameters:
2652 **		e -- envelope to set it in.
2653 **
2654 **	Returns:
2655 **		none.
2656 */
2657 
2658 static char	Base60Code[] =	"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
2659 
2660 void
2661 assign_queueid(e)
2662 	register ENVELOPE *e;
2663 {
2664 	pid_t pid = getpid();
2665 	static char cX = 0;
2666 	static long random_offset;
2667 	struct tm *tm;
2668 	char idbuf[MAXQFNAME - 2];
2669 
2670 	if (e->e_id != NULL)
2671 		return;
2672 
2673 	/* see if we need to get a new base time/pid */
2674 	if (cX >= 60 || LastQueueTime == 0 || LastQueuePid != pid)
2675 	{
2676 		time_t then = LastQueueTime;
2677 
2678 		/* if the first time through, pick a random offset */
2679 		if (LastQueueTime == 0)
2680 			random_offset = get_random();
2681 
2682 		while ((LastQueueTime = curtime()) == then &&
2683 		       LastQueuePid == pid)
2684 		{
2685 			(void) sleep(1);
2686 		}
2687 		LastQueuePid = getpid();
2688 		cX = 0;
2689 	}
2690 	if (tTd(7, 50))
2691 		dprintf("assign_queueid: random_offset = %ld (%d)\n",
2692 			random_offset, (int)(cX + random_offset) % 60);
2693 
2694 	tm = gmtime(&LastQueueTime);
2695 	idbuf[0] = Base60Code[tm->tm_year % 60];
2696 	idbuf[1] = Base60Code[tm->tm_mon];
2697 	idbuf[2] = Base60Code[tm->tm_mday];
2698 	idbuf[3] = Base60Code[tm->tm_hour];
2699 	idbuf[4] = Base60Code[tm->tm_min];
2700 	idbuf[5] = Base60Code[tm->tm_sec];
2701 	idbuf[6] = Base60Code[((int)cX++ + random_offset) % 60];
2702 	(void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d",
2703 			(int) LastQueuePid);
2704 	e->e_id = newstr(idbuf);
2705 	define('i', e->e_id, e);
2706 	e->e_queuedir = NOQDIR;
2707 	if (tTd(7, 1))
2708 		dprintf("assign_queueid: assigned id %s, e=%lx\n",
2709 			e->e_id, (u_long) e);
2710 	if (LogLevel > 93)
2711 		sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
2712 }
2713 /*
2714 **  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
2715 **
2716 **	Make sure one PID can't be used by two processes in any one second.
2717 **
2718 **		If the system rotates PIDs fast enough, may get the
2719 **		same pid in the same second for two distinct processes.
2720 **		This will interfere with the queue file naming system.
2721 **
2722 **	Parameters:
2723 **		none
2724 **
2725 **	Returns:
2726 **		none
2727 */
2728 void
2729 sync_queue_time()
2730 {
2731 # if FAST_PID_RECYCLE
2732 	if (OpMode != MD_TEST &&
2733 	    OpMode != MD_VERIFY &&
2734 	    LastQueueTime > 0 &&
2735 	    LastQueuePid == getpid() &&
2736 	    curtime() == LastQueueTime)
2737 		(void) sleep(1);
2738 # endif /* FAST_PID_RECYCLE */
2739 }
2740 /*
2741 **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
2742 **
2743 **	Parameters:
2744 **		e -- the envelope to unlock.
2745 **
2746 **	Returns:
2747 **		none
2748 **
2749 **	Side Effects:
2750 **		unlocks the queue for `e'.
2751 */
2752 
2753 void
2754 unlockqueue(e)
2755 	ENVELOPE *e;
2756 {
2757 	if (tTd(51, 4))
2758 		dprintf("unlockqueue(%s)\n",
2759 			e->e_id == NULL ? "NOQUEUE" : e->e_id);
2760 
2761 
2762 	/* if there is a lock file in the envelope, close it */
2763 	if (e->e_lockfp != NULL)
2764 		(void) fclose(e->e_lockfp);
2765 	e->e_lockfp = NULL;
2766 
2767 	/* don't create a queue id if we don't already have one */
2768 	if (e->e_id == NULL)
2769 		return;
2770 
2771 	/* remove the transcript */
2772 	if (LogLevel > 87)
2773 		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
2774 	if (!tTd(51, 104))
2775 		xunlink(queuename(e, 'x'));
2776 
2777 }
2778 /*
2779 **  SETCTLUSER -- create a controlling address
2780 **
2781 **	Create a fake "address" given only a local login name; this is
2782 **	used as a "controlling user" for future recipient addresses.
2783 **
2784 **	Parameters:
2785 **		user -- the user name of the controlling user.
2786 **		qfver -- the version stamp of this qf file.
2787 **
2788 **	Returns:
2789 **		An address descriptor for the controlling user.
2790 **
2791 **	Side Effects:
2792 **		none.
2793 */
2794 
2795 static ADDRESS *
2796 setctluser(user, qfver)
2797 	char *user;
2798 	int qfver;
2799 {
2800 	register ADDRESS *a;
2801 	struct passwd *pw;
2802 	char *p;
2803 
2804 	/*
2805 	**  See if this clears our concept of controlling user.
2806 	*/
2807 
2808 	if (user == NULL || *user == '\0')
2809 		return NULL;
2810 
2811 	/*
2812 	**  Set up addr fields for controlling user.
2813 	*/
2814 
2815 	a = (ADDRESS *) xalloc(sizeof *a);
2816 	memset((char *) a, '\0', sizeof *a);
2817 
2818 	if (*user == '\0')
2819 	{
2820 		p = NULL;
2821 		a->q_user = newstr(DefUser);
2822 	}
2823 	else if (*user == ':')
2824 	{
2825 		p = &user[1];
2826 		a->q_user = newstr(p);
2827 	}
2828 	else
2829 	{
2830 		p = strtok(user, ":");
2831 		a->q_user = newstr(user);
2832 		if (qfver >= 2)
2833 		{
2834 			if ((p = strtok(NULL, ":")) != NULL)
2835 				a->q_uid = atoi(p);
2836 			if ((p = strtok(NULL, ":")) != NULL)
2837 				a->q_gid = atoi(p);
2838 			if ((p = strtok(NULL, ":")) != NULL)
2839 				a->q_flags |= QGOODUID;
2840 		}
2841 		else if ((pw = sm_getpwnam(user)) != NULL)
2842 		{
2843 			if (strcmp(pw->pw_dir, "/") == 0)
2844 				a->q_home = "";
2845 			else
2846 				a->q_home = newstr(pw->pw_dir);
2847 			a->q_uid = pw->pw_uid;
2848 			a->q_gid = pw->pw_gid;
2849 			a->q_flags |= QGOODUID;
2850 		}
2851 	}
2852 
2853 	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr" */
2854 	a->q_mailer = LocalMailer;
2855 	if (p == NULL)
2856 		a->q_paddr = newstr(a->q_user);
2857 	else
2858 		a->q_paddr = newstr(p);
2859 	return a;
2860 }
2861 /*
2862 **  LOSEQFILE -- save the qf as Qf and try to let someone know
2863 **
2864 **	Parameters:
2865 **		e -- the envelope (e->e_id will be used).
2866 **		why -- reported to whomever can hear.
2867 **
2868 **	Returns:
2869 **		none.
2870 */
2871 
2872 # define LOSEQF_LETTER 'Q'
2873 
2874 void
2875 loseqfile(e, why)
2876 	register ENVELOPE *e;
2877 	char *why;
2878 {
2879 	char *p;
2880 	char buf[MAXPATHLEN];
2881 
2882 	if (e == NULL || e->e_id == NULL)
2883 		return;
2884 	p = queuename(e, 'q');
2885 	if (strlen(p) >= (SIZE_T) sizeof buf)
2886 		return;
2887 	(void) strlcpy(buf, p, sizeof buf);
2888 	p = queuename(e, LOSEQF_LETTER);
2889 	if (rename(buf, p) < 0)
2890 		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2891 	else if (LogLevel > 0)
2892 		sm_syslog(LOG_ALERT, e->e_id,
2893 			  "Losing %s: %s", buf, why);
2894 }
2895 /*
2896 **  QID_PRINTNAME -- create externally printable version of queue id
2897 **
2898 **	Parameters:
2899 **		e -- the envelope.
2900 **
2901 **	Returns:
2902 **		a printable version
2903 */
2904 
2905 char *
2906 qid_printname(e)
2907 	ENVELOPE *e;
2908 {
2909 	char *id;
2910 	static char idbuf[MAXQFNAME + 34];
2911 
2912 	if (e == NULL)
2913 		return "";
2914 
2915 	if (e->e_id == NULL)
2916 		id = "";
2917 	else
2918 		id = e->e_id;
2919 
2920 	if (e->e_queuedir == NOQDIR)
2921 		return id;
2922 
2923 	(void) snprintf(idbuf, sizeof idbuf, "%.32s/%s",
2924 			QPaths[e->e_queuedir].qp_name, id);
2925 	return idbuf;
2926 }
2927 /*
2928 **  QID_PRINTQUEUE -- create full version of queue directory for df files
2929 **
2930 **	Parameters:
2931 **		queuedir -- the short version of the queue directory
2932 **
2933 **	Returns:
2934 **		the full pathname to the queue (static)
2935 */
2936 
2937 char *
2938 qid_printqueue(queuedir)
2939 	int queuedir;
2940 {
2941 	char *subdir;
2942 	static char dir[MAXPATHLEN];
2943 
2944 	if (queuedir == NOQDIR)
2945 		return QueueDir;
2946 
2947 	if (strcmp(QPaths[queuedir].qp_name, ".") == 0)
2948 		subdir = NULL;
2949 	else
2950 		subdir = QPaths[queuedir].qp_name;
2951 
2952 	(void) snprintf(dir, sizeof dir, "%s%s%s%s", QueueDir,
2953 			subdir == NULL ? "" : "/",
2954 			subdir == NULL ? "" : subdir,
2955 			(bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
2956 	return dir;
2957 }
2958 /*
2959 **  SETNEWQUEUE -- Sets a new queue directory
2960 **
2961 **	Assign a queue directory to an envelope and store the directory
2962 **	in e->e_queuedir.  The queue is chosen at random.
2963 **
2964 **	This routine may be improved in the future to allow for more
2965 **	elaborate queueing schemes.  Suggestions and code contributions
2966 **	are welcome.
2967 **
2968 **	Parameters:
2969 **		e -- envelope to assign a queue for.
2970 **
2971 **	Returns:
2972 **		none.
2973 */
2974 
2975 void
2976 setnewqueue(e)
2977 	ENVELOPE *e;
2978 {
2979 	int idx;
2980 
2981 	if (tTd(41, 20))
2982 		dprintf("setnewqueue: called\n");
2983 
2984 	if (e->e_queuedir != NOQDIR)
2985 	{
2986 		if (tTd(41, 20))
2987 			dprintf("setnewqueue: e_queuedir already assigned (%s)\n",
2988 				qid_printqueue(e->e_queuedir));
2989 		return;
2990 	}
2991 
2992 	if (NumQueues == 1)
2993 		idx = 0;
2994 	else
2995 	{
2996 #if RANDOMSHIFT
2997 		/* lower bits are not random "enough", select others */
2998 		idx = (get_random() >> RANDOMSHIFT) % NumQueues;
2999 #else /* RANDOMSHIFT */
3000 		idx = get_random() % NumQueues;
3001 #endif /* RANDOMSHIFT */
3002 		if (tTd(41, 15))
3003 			dprintf("setnewqueue: get_random() %% %d = %d\n",
3004 				NumQueues, idx);
3005 	}
3006 
3007 	e->e_queuedir = idx;
3008 	if (tTd(41, 3))
3009 		dprintf("setnewqueue: Assigned queue directory %s\n",
3010 			qid_printqueue(e->e_queuedir));
3011 }
3012 
3013 /*
3014 **  CHKQDIR -- check a queue directory
3015 **
3016 **	Parameters:
3017 **		name -- name of queue directory
3018 **		sff -- flags for safefile()
3019 **
3020 **	Returns:
3021 **		is it a queue directory?
3022 */
3023 
3024 static bool
3025 chkqdir(name, sff)
3026 	char *name;
3027 	long sff;
3028 {
3029 	struct stat statb;
3030 	int i;
3031 
3032 # if HASLSTAT
3033 	if (lstat(name, &statb) < 0)
3034 # else /* HASLSTAT */
3035 	if (stat(name, &statb) < 0)
3036 # endif /* HASLSTAT */
3037 	{
3038 		if (tTd(41, 2))
3039 			dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
3040 				name, errstring(errno));
3041 		return FALSE;
3042 	}
3043 # if HASLSTAT
3044 	if (S_ISLNK(statb.st_mode))
3045 	{
3046 		/*
3047 		**  For a symlink we need to make sure the
3048 		**  target is a directory
3049 		*/
3050 		if (stat(name, &statb) < 0)
3051 		{
3052 			if (tTd(41, 2))
3053 				dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
3054 					name, errstring(errno));
3055 			return FALSE;
3056 		}
3057 	}
3058 # endif /* HASLSTAT */
3059 
3060 	if (!S_ISDIR(statb.st_mode))
3061 	{
3062 		if (tTd(41, 2))
3063 			dprintf("multiqueue_cache: \"%s\": Not a directory\n",
3064 				name);
3065 		return FALSE;
3066 	}
3067 
3068 	/* Print a warning if unsafe (but still use it) */
3069 	i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
3070 	if (i != 0 && tTd(41, 2))
3071 		dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
3072 			name, errstring(i));
3073 	return TRUE;
3074 }
3075 
3076 /*
3077 **  MULTIQUEUE_CACHE -- cache a list of paths to queues.
3078 **
3079 **	Each potential queue is checked as the cache is built.
3080 **	Thereafter, each is blindly trusted.
3081 **	Note that we can be called again after a timeout to rebuild
3082 **	(although code for that is not ready yet).
3083 **
3084 **	Parameters:
3085 **		none
3086 **
3087 **	Returns:
3088 **		none
3089 */
3090 
3091 void
3092 multiqueue_cache()
3093 {
3094 	register DIR *dp;
3095 	register struct dirent *d;
3096 	char *cp;
3097 	int i, len;
3098 	int slotsleft = 0;
3099 	long sff = SFF_ANYFILE;
3100 	char qpath[MAXPATHLEN];
3101 	char subdir[MAXPATHLEN];
3102 
3103 	if (tTd(41, 20))
3104 		dprintf("multiqueue_cache: called\n");
3105 
3106 	if (NumQueues != 0 && QPaths != NULL)
3107 	{
3108 		for (i = 0; i < NumQueues; i++)
3109 		{
3110 			if (QPaths[i].qp_name != NULL)
3111 				(void) free(QPaths[i].qp_name);
3112 		}
3113 		(void) free((char *)QPaths);
3114 		QPaths = NULL;
3115 		NumQueues = 0;
3116 	}
3117 
3118 	/* If running as root, allow safedirpath() checks to use privs */
3119 	if (RunAsUid == 0)
3120 		sff |= SFF_ROOTOK;
3121 
3122 	(void) snprintf(qpath, sizeof qpath, "%s", QueueDir);
3123 	len = strlen(qpath) - 1;
3124 	cp = &qpath[len];
3125 	if (*cp == '*')
3126 	{
3127 		*cp = '\0';
3128 		if ((cp = strrchr(qpath, '/')) == NULL)
3129 		{
3130 			syserr("QueueDirectory: can not wildcard relative path");
3131 			if (tTd(41, 2))
3132 				dprintf("multiqueue_cache: \"%s\": Can not wildcard relative path.\n",
3133 					QueueDir);
3134 			ExitStat = EX_CONFIG;
3135 			return;
3136 		}
3137 		if (cp == qpath)
3138 		{
3139 			/*
3140 			**  Special case of top level wildcard, like /foo*
3141 			*/
3142 
3143 			(void) snprintf(qpath + 1, sizeof qpath - 1,
3144 					"%s", qpath);
3145 			++cp;
3146 		}
3147 		*(cp++) = '\0';
3148 		len = strlen(cp);
3149 
3150 		if (tTd(41, 2))
3151 			dprintf("multiqueue_cache: prefix=\"%s\"\n", cp);
3152 
3153 		QueueDir = newstr(qpath);
3154 
3155 		/*
3156 		**  XXX Should probably wrap this whole loop in a timeout
3157 		**  in case some wag decides to NFS mount the queues.
3158 		*/
3159 
3160 		/* test path to get warning messages */
3161 		i= safedirpath(QueueDir, RunAsUid, RunAsGid, NULL, sff, 0, 0);
3162 		if (i != 0 && tTd(41, 2))
3163 			dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
3164 				QueueDir, errstring(i));
3165 
3166 		if (chdir(QueueDir) < 0)
3167 		{
3168 			syserr("can not chdir(%s)", QueueDir);
3169 			if (tTd(41, 2))
3170 				dprintf("multiqueue_cache: \"%s\": %s\n",
3171 					qpath, errstring(errno));
3172 			ExitStat = EX_CONFIG;
3173 			return;
3174 		}
3175 
3176 		if ((dp = opendir(".")) == NULL)
3177 		{
3178 			syserr("can not opendir(%s)", QueueDir);
3179 			if (tTd(41, 2))
3180 				dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
3181 					QueueDir, errstring(errno));
3182 			ExitStat = EX_CONFIG;
3183 			return;
3184 		}
3185 		while ((d = readdir(dp)) != NULL)
3186 		{
3187 			if (strncmp(d->d_name, cp, len) != 0)
3188 			{
3189 				if (tTd(41, 5))
3190 					dprintf("multiqueue_cache: \"%s\", skipped\n",
3191 						d->d_name);
3192 				continue;
3193 			}
3194 			if (!chkqdir(d->d_name, sff))
3195 				continue;
3196 
3197 			if (QPaths == NULL)
3198 			{
3199 				slotsleft = 20;
3200 				QPaths = (QPATHS *)xalloc((sizeof *QPaths) *
3201 							  slotsleft);
3202 				NumQueues = 0;
3203 			}
3204 			else if (slotsleft < 1)
3205 			{
3206 				QPaths = (QPATHS *)realloc((char *)QPaths,
3207 							  (sizeof *QPaths) *
3208 							  (NumQueues + 10));
3209 				if (QPaths == NULL)
3210 				{
3211 					(void) closedir(dp);
3212 					return;
3213 				}
3214 				slotsleft += 10;
3215 			}
3216 
3217 			/* check subdirs */
3218 			QPaths[NumQueues].qp_subdirs = QP_NOSUB;
3219 			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3220 					qpath, d->d_name, "qf");
3221 			if (chkqdir(subdir, sff))
3222 				QPaths[NumQueues].qp_subdirs |= QP_SUBQF;
3223 
3224 			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3225 					qpath, d->d_name, "df");
3226 			if (chkqdir(subdir, sff))
3227 				QPaths[NumQueues].qp_subdirs |= QP_SUBDF;
3228 
3229 			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3230 					qpath, d->d_name, "xf");
3231 			if (chkqdir(subdir, sff))
3232 				QPaths[NumQueues].qp_subdirs |= QP_SUBXF;
3233 
3234 			/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
3235 			/* maybe even - 17 (subdirs) */
3236 			QPaths[NumQueues].qp_name = newstr(d->d_name);
3237 			if (tTd(41, 2))
3238 				dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
3239 					NumQueues, d->d_name,
3240 					QPaths[NumQueues].qp_subdirs);
3241 			NumQueues++;
3242 			slotsleft--;
3243 		}
3244 		(void) closedir(dp);
3245 	}
3246 	if (NumQueues == 0)
3247 	{
3248 		if (*cp != '*' && tTd(41, 2))
3249 			dprintf("multiqueue_cache: \"%s\": No wildcard suffix character\n",
3250 				QueueDir);
3251 		QPaths = (QPATHS *)xalloc(sizeof *QPaths);
3252 		QPaths[0].qp_name = newstr(".");
3253 		QPaths[0].qp_subdirs = QP_NOSUB;
3254 		NumQueues = 1;
3255 
3256 		/* test path to get warning messages */
3257 		(void) safedirpath(QueueDir, RunAsUid, RunAsGid,
3258 				   NULL, sff, 0, 0);
3259 		if (chdir(QueueDir) < 0)
3260 		{
3261 			syserr("can not chdir(%s)", QueueDir);
3262 			if (tTd(41, 2))
3263 				dprintf("multiqueue_cache: \"%s\": %s\n",
3264 					QueueDir, errstring(errno));
3265 			ExitStat = EX_CONFIG;
3266 		}
3267 
3268 		/* check subdirs */
3269 		(void) snprintf(subdir, sizeof subdir, "%s/qf", QueueDir);
3270 		if (chkqdir(subdir, sff))
3271 			QPaths[0].qp_subdirs |= QP_SUBQF;
3272 
3273 		(void) snprintf(subdir, sizeof subdir, "%s/df",	QueueDir);
3274 		if (chkqdir(subdir, sff))
3275 			QPaths[0].qp_subdirs |= QP_SUBDF;
3276 
3277 		(void) snprintf(subdir, sizeof subdir, "%s/xf", QueueDir);
3278 		if (chkqdir(subdir, sff))
3279 			QPaths[0].qp_subdirs |= QP_SUBXF;
3280 	}
3281 }
3282 
3283 # if 0
3284 /*
3285 **  HASHFQN -- calculate a hash value for a fully qualified host name
3286 **
3287 **	Arguments:
3288 **		fqn -- an all lower-case host.domain string
3289 **		buckets -- the number of buckets (queue directories)
3290 **
3291 **	Returns:
3292 **		a bucket number (signed integer)
3293 **		-1 on error
3294 **
3295 **	Contributed by Exactis.com, Inc.
3296 */
3297 
3298 int
3299 hashfqn(fqn, buckets)
3300 	register char *fqn;
3301 	int buckets;
3302 {
3303 	register char *p;
3304 	register int h = 0, hash, cnt;
3305 #  define WATERINC (1000)
3306 
3307 	if (fqn == NULL)
3308 		return -1;
3309 
3310 	/*
3311 	**  A variation on the gdb hash
3312 	**  This is the best as of Feb 19, 1996 --bcx
3313 	*/
3314 
3315 	p = fqn;
3316 	h = 0x238F13AF * strlen(p);
3317 	for (cnt = 0; *p != 0; ++p, cnt++)
3318 	{
3319 		h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
3320 	}
3321 	h = (1103515243 * h + 12345) & 0x7FFFFFFF;
3322 	if (buckets < 2)
3323 		hash = 0;
3324 	else
3325 		hash = (h % buckets);
3326 
3327 	return hash;
3328 }
3329 # endif /* 0 */
3330 
3331 # if _FFR_QUEUEDELAY
3332 /*
3333 **  QUEUEDELAY -- compute queue delay time
3334 **
3335 **	Parameters:
3336 **		e -- the envelope to queue up.
3337 **
3338 **	Returns:
3339 **		queue delay time
3340 **
3341 **	Side Effects:
3342 **		may change e_queuedelay
3343 */
3344 
3345 static time_t
3346 queuedelay(e)
3347 	ENVELOPE *e;
3348 {
3349 	time_t qd;
3350 
3351 	if (e->e_queuealg == QD_EXP)
3352 	{
3353 		if (e->e_queuedelay == 0)
3354 			e->e_queuedelay = QueueInitDelay;
3355 		else
3356 		{
3357 			e->e_queuedelay *= 2;
3358 			if (e->e_queuedelay > QueueMaxDelay)
3359 				e->e_queuedelay = QueueMaxDelay;
3360 		}
3361 		qd = e->e_queuedelay;
3362 	}
3363 	else
3364 		qd = MinQueueAge;
3365 	return qd;
3366 }
3367 # endif /* _FFR_QUEUEDELAY */
3368 #endif /* QUEUE */
3369