xref: /original-bsd/usr.sbin/sendmail/src/queue.c (revision c4f3b704)
1 /*
2  * Copyright (c) 1983, 1995 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 # include "sendmail.h"
10 
11 #ifndef lint
12 #ifdef QUEUE
13 static char sccsid[] = "@(#)queue.c	8.85 (Berkeley) 05/28/95 (with queueing)";
14 #else
15 static char sccsid[] = "@(#)queue.c	8.85 (Berkeley) 05/28/95 (without queueing)";
16 #endif
17 #endif /* not lint */
18 
19 # include <errno.h>
20 # include <dirent.h>
21 
22 # ifdef QUEUE
23 
24 /*
25 **  Work queue.
26 */
27 
28 struct work
29 {
30 	char		*w_name;	/* name of control file */
31 	char		*w_host;	/* name of recipient host */
32 	bool		w_lock;		/* is message locked? */
33 	long		w_pri;		/* priority of message, see below */
34 	time_t		w_ctime;	/* creation time of message */
35 	struct work	*w_next;	/* next in queue */
36 };
37 
38 typedef struct work	WORK;
39 
40 WORK	*WorkQ;			/* queue of things to be done */
41 
42 #define QF_VERSION	1	/* version number of this queue format */
43 /*
44 **  QUEUEUP -- queue a message up for future transmission.
45 **
46 **	Parameters:
47 **		e -- the envelope to queue up.
48 **		queueall -- if TRUE, queue all addresses, rather than
49 **			just those with the QQUEUEUP flag set.
50 **		announce -- if TRUE, tell when you are queueing up.
51 **
52 **	Returns:
53 **		none.
54 **
55 **	Side Effects:
56 **		The current request are saved in a control file.
57 **		The queue file is left locked.
58 */
59 
60 void
61 queueup(e, queueall, announce)
62 	register ENVELOPE *e;
63 	bool queueall;
64 	bool announce;
65 {
66 	char *qf;
67 	register FILE *tfp;
68 	register HDR *h;
69 	register ADDRESS *q;
70 	int fd;
71 	int i;
72 	bool newid;
73 	register char *p;
74 	MAILER nullmailer;
75 	MCI mcibuf;
76 	char buf[MAXLINE], tf[MAXLINE];
77 	extern void printctladdr __P((ADDRESS *, FILE *));
78 
79 	/*
80 	**  Create control file.
81 	*/
82 
83 	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
84 
85 	/* if newid, queuename will create a locked qf file in e->lockfp */
86 	strcpy(tf, queuename(e, 't'));
87 	tfp = e->e_lockfp;
88 	if (tfp == NULL)
89 		newid = FALSE;
90 
91 	/* if newid, just write the qf file directly (instead of tf file) */
92 	if (!newid)
93 	{
94 		/* get a locked tf file */
95 		for (i = 0; i < 128; i++)
96 		{
97 			fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
98 			if (fd < 0)
99 			{
100 				if (errno != EEXIST)
101 					break;
102 #ifdef LOG
103 				if (LogLevel > 0 && (i % 32) == 0)
104 					syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s",
105 						tf, geteuid(), errstring(errno));
106 #endif
107 			}
108 			else
109 			{
110 				if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
111 					break;
112 #ifdef LOG
113 				else if (LogLevel > 0 && (i % 32) == 0)
114 					syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
115 						tf, errstring(errno));
116 #endif
117 				close(fd);
118 			}
119 
120 			if ((i % 32) == 31)
121 			{
122 				/* save the old temp file away */
123 				(void) rename(tf, queuename(e, 'T'));
124 			}
125 			else
126 				sleep(i % 32);
127 		}
128 		if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
129 		{
130 			printopenfds(TRUE);
131 			syserr("!queueup: cannot create queue temp file %s, uid=%d",
132 				tf, geteuid());
133 		}
134 	}
135 
136 	if (tTd(40, 1))
137 		printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id,
138 			newid ? " (new id)" : "", queueall);
139 	if (tTd(40, 3))
140 	{
141 		extern void printenvflags();
142 
143 		printf("  e_flags=");
144 		printenvflags(e);
145 	}
146 	if (tTd(40, 32))
147 	{
148 		printf("  sendq=");
149 		printaddr(e->e_sendqueue, TRUE);
150 	}
151 	if (tTd(40, 9))
152 	{
153 		printf("  tfp=");
154 		dumpfd(fileno(tfp), TRUE, FALSE);
155 		printf("  lockfp=");
156 		if (e->e_lockfp == NULL)
157 			printf("NULL\n");
158 		else
159 			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
160 	}
161 
162 	/*
163 	**  If there is no data file yet, create one.
164 	*/
165 
166 	if (!bitset(EF_HAS_DF, e->e_flags))
167 	{
168 		register FILE *dfp;
169 		char dfname[20];
170 		struct stat stbuf;
171 
172 		strcpy(dfname, queuename(e, 'd'));
173 		fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
174 		if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
175 			syserr("!queueup: cannot create data temp file %s, uid=%d",
176 				dfname, geteuid());
177 		if (fstat(fd, &stbuf) < 0)
178 			e->e_dfino = -1;
179 		else
180 		{
181 			e->e_dfdev = stbuf.st_dev;
182 			e->e_dfino = stbuf.st_ino;
183 		}
184 		e->e_flags |= EF_HAS_DF;
185 		bzero(&mcibuf, sizeof mcibuf);
186 		mcibuf.mci_out = dfp;
187 		mcibuf.mci_mailer = FileMailer;
188 		(*e->e_putbody)(&mcibuf, e, NULL);
189 		(void) xfclose(dfp, "queueup dfp", e->e_id);
190 		e->e_putbody = putbody;
191 	}
192 
193 	/*
194 	**  Output future work requests.
195 	**	Priority and creation time should be first, since
196 	**	they are required by orderq.
197 	*/
198 
199 	/* output queue version number (must be first!) */
200 	fprintf(tfp, "V%d\n", QF_VERSION);
201 
202 	/* output message priority */
203 	fprintf(tfp, "P%ld\n", e->e_msgpriority);
204 
205 	/* output creation time */
206 	fprintf(tfp, "T%ld\n", e->e_ctime);
207 
208 	/* output last delivery time */
209 	fprintf(tfp, "K%ld\n", e->e_dtime);
210 
211 	/* output number of delivery attempts */
212 	fprintf(tfp, "N%d\n", e->e_ntries);
213 
214 	/* output inode number of data file */
215 	/* XXX should probably include device major/minor too */
216 	if (e->e_dfino != -1)
217 		fprintf(tfp, "I%d/%d/%ld\n",
218 			major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino);
219 
220 	/* output body type */
221 	if (e->e_bodytype != NULL)
222 		fprintf(tfp, "B%s\n", e->e_bodytype);
223 
224 	/* message from envelope, if it exists */
225 	if (e->e_message != NULL)
226 		fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
227 
228 	/* send various flag bits through */
229 	p = buf;
230 	if (bitset(EF_WARNING, e->e_flags))
231 		*p++ = 'w';
232 	if (bitset(EF_RESPONSE, e->e_flags))
233 		*p++ = 'r';
234 	if (bitset(EF_HAS8BIT, e->e_flags))
235 		*p++ = '8';
236 	*p++ = '\0';
237 	if (buf[0] != '\0')
238 		fprintf(tfp, "F%s\n", buf);
239 
240 	/* $r and $s and $_ macro values */
241 	if ((p = macvalue('r', e)) != NULL)
242 		fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
243 	if ((p = macvalue('s', e)) != NULL)
244 		fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
245 	if ((p = macvalue('_', e)) != NULL)
246 		fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
247 
248 	/* output name of sender */
249 	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
250 		p = e->e_sender;
251 	else
252 		p = e->e_from.q_paddr;
253 	fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
254 
255 	/* output ESMTP-supplied "original" information */
256 	if (e->e_envid != NULL)
257 		fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
258 
259 	/* output list of recipient addresses */
260 	printctladdr(NULL, NULL);
261 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
262 	{
263 		if (bitset(QQUEUEUP, q->q_flags) ||
264 		    (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
265 		{
266 			printctladdr(q, tfp);
267 			if (q->q_orcpt != NULL)
268 				fprintf(tfp, "Q%s\n",
269 					denlstring(q->q_orcpt, TRUE, FALSE));
270 			putc('R', tfp);
271 			if (bitset(QPRIMARY, q->q_flags))
272 				putc('P', tfp);
273 			if (bitset(QPINGONSUCCESS, q->q_flags))
274 				putc('S', tfp);
275 			if (bitset(QPINGONFAILURE, q->q_flags))
276 				putc('F', tfp);
277 			if (bitset(QPINGONDELAY, q->q_flags))
278 				putc('D', tfp);
279 			putc(':', tfp);
280 			fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
281 			if (announce)
282 			{
283 				e->e_to = q->q_paddr;
284 				message("queued");
285 				if (LogLevel > 8)
286 					logdelivery(NULL, NULL, "queued",
287 						    NULL, (time_t) 0, e);
288 				e->e_to = NULL;
289 			}
290 			if (tTd(40, 1))
291 			{
292 				printf("queueing ");
293 				printaddr(q, FALSE);
294 			}
295 		}
296 	}
297 
298 	/*
299 	**  Output headers for this message.
300 	**	Expand macros completely here.  Queue run will deal with
301 	**	everything as absolute headers.
302 	**		All headers that must be relative to the recipient
303 	**		can be cracked later.
304 	**	We set up a "null mailer" -- i.e., a mailer that will have
305 	**	no effect on the addresses as they are output.
306 	*/
307 
308 	bzero((char *) &nullmailer, sizeof nullmailer);
309 	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
310 			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
311 	nullmailer.m_eol = "\n";
312 	bzero(&mcibuf, sizeof mcibuf);
313 	mcibuf.mci_mailer = &nullmailer;
314 	mcibuf.mci_out = tfp;
315 
316 	define('g', "\201f", e);
317 	for (h = e->e_header; h != NULL; h = h->h_link)
318 	{
319 		extern bool bitzerop();
320 
321 		/* don't output null headers */
322 		if (h->h_value == NULL || h->h_value[0] == '\0')
323 			continue;
324 
325 		/* don't output resent headers on non-resent messages */
326 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
327 			continue;
328 
329 		/* expand macros; if null, don't output header at all */
330 		if (bitset(H_DEFAULT, h->h_flags))
331 		{
332 			(void) expand(h->h_value, buf, sizeof buf, e);
333 			if (buf[0] == '\0')
334 				continue;
335 		}
336 
337 		/* output this header */
338 		fprintf(tfp, "H");
339 
340 		/* if conditional, output the set of conditions */
341 		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
342 		{
343 			int j;
344 
345 			(void) putc('?', tfp);
346 			for (j = '\0'; j <= '\177'; j++)
347 				if (bitnset(j, h->h_mflags))
348 					(void) putc(j, tfp);
349 			(void) putc('?', tfp);
350 		}
351 
352 		/* output the header: expand macros, convert addresses */
353 		if (bitset(H_DEFAULT, h->h_flags))
354 		{
355 			fprintf(tfp, "%s: %s\n", h->h_field, buf);
356 		}
357 		else if (bitset(H_FROM|H_RCPT, h->h_flags))
358 		{
359 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
360 			FILE *savetrace = TrafficLogFile;
361 
362 			TrafficLogFile = NULL;
363 
364 			if (bitset(H_FROM, h->h_flags))
365 				oldstyle = FALSE;
366 
367 			commaize(h, h->h_value, oldstyle, &mcibuf, e);
368 
369 			TrafficLogFile = savetrace;
370 		}
371 		else
372 			fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
373 	}
374 
375 	/*
376 	**  Clean up.
377 	*/
378 
379 	if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
380 	{
381 		if (newid)
382 			syserr("!552 Error writing control file %s", tf);
383 		else
384 			syserr("!452 Error writing control file %s", tf);
385 	}
386 
387 	if (!newid)
388 	{
389 		/* rename (locked) tf to be (locked) qf */
390 		qf = queuename(e, 'q');
391 		if (rename(tf, qf) < 0)
392 			syserr("cannot rename(%s, %s), uid=%d",
393 				tf, qf, geteuid());
394 
395 		/* close and unlock old (locked) qf */
396 		if (e->e_lockfp != NULL)
397 			(void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
398 		e->e_lockfp = tfp;
399 	}
400 	else
401 		qf = tf;
402 	errno = 0;
403 	e->e_flags |= EF_INQUEUE;
404 
405 # ifdef LOG
406 	/* save log info */
407 	if (LogLevel > 79)
408 		syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf);
409 # endif /* LOG */
410 
411 	if (tTd(40, 1))
412 		printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
413 	return;
414 }
415 
416 void
417 printctladdr(a, tfp)
418 	register ADDRESS *a;
419 	FILE *tfp;
420 {
421 	char *uname;
422 	register struct passwd *pw;
423 	register ADDRESS *q;
424 	uid_t uid;
425 	static ADDRESS *lastctladdr;
426 	static uid_t lastuid;
427 
428 	/* initialization */
429 	if (a == NULL || a->q_alias == NULL || tfp == NULL)
430 	{
431 		if (lastctladdr != NULL && tfp != NULL)
432 			fprintf(tfp, "C\n");
433 		lastctladdr = NULL;
434 		lastuid = 0;
435 		return;
436 	}
437 
438 	/* find the active uid */
439 	q = getctladdr(a);
440 	if (q == NULL)
441 		uid = 0;
442 	else
443 		uid = q->q_uid;
444 	a = a->q_alias;
445 
446 	/* check to see if this is the same as last time */
447 	if (lastctladdr != NULL && uid == lastuid &&
448 	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
449 		return;
450 	lastuid = uid;
451 	lastctladdr = a;
452 
453 	if (uid == 0 || (pw = sm_getpwuid(uid)) == NULL)
454 		uname = "";
455 	else
456 		uname = pw->pw_name;
457 
458 	fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE));
459 }
460 /*
461 **  RUNQUEUE -- run the jobs in the queue.
462 **
463 **	Gets the stuff out of the queue in some presumably logical
464 **	order and processes them.
465 **
466 **	Parameters:
467 **		forkflag -- TRUE if the queue scanning should be done in
468 **			a child process.  We double-fork so it is not our
469 **			child and we don't have to clean up after it.
470 **
471 **	Returns:
472 **		none.
473 **
474 **	Side Effects:
475 **		runs things in the mail queue.
476 */
477 
478 ENVELOPE	QueueEnvelope;		/* the queue run envelope */
479 
480 void
481 runqueue(forkflag)
482 	bool forkflag;
483 {
484 	register ENVELOPE *e;
485 	int njobs;
486 	int sequenceno = 0;
487 	extern ENVELOPE BlankEnvelope;
488 
489 	/*
490 	**  If no work will ever be selected, don't even bother reading
491 	**  the queue.
492 	*/
493 
494 	CurrentLA = getla();	/* get load average */
495 
496 	if (shouldqueue(0L, curtime()))
497 	{
498 		char *msg = "Skipping queue run -- load average too high";
499 
500 		if (Verbose)
501 			printf("%s\n", msg);
502 #ifdef LOG
503 		if (LogLevel > 8)
504 			syslog(LOG_INFO, "runqueue: %s", msg);
505 #endif
506 		if (forkflag && QueueIntvl != 0)
507 			(void) setevent(QueueIntvl, runqueue, TRUE);
508 		return;
509 	}
510 
511 	/*
512 	**  See if we want to go off and do other useful work.
513 	*/
514 
515 	if (forkflag)
516 	{
517 		int pid;
518 #ifdef SIGCHLD
519 		extern void reapchild();
520 
521 		(void) setsignal(SIGCHLD, reapchild);
522 #endif
523 
524 		pid = dofork();
525 		if (pid != 0)
526 		{
527 			/* parent -- pick up intermediate zombie */
528 #ifndef SIGCHLD
529 			(void) waitfor(pid);
530 #endif /* SIGCHLD */
531 			if (QueueIntvl != 0)
532 				(void) setevent(QueueIntvl, runqueue, TRUE);
533 			return;
534 		}
535 		/* child -- double fork */
536 #ifndef SIGCHLD
537 		if (fork() != 0)
538 			exit(EX_OK);
539 #else /* SIGCHLD */
540 		(void) setsignal(SIGCHLD, SIG_DFL);
541 #endif /* SIGCHLD */
542 	}
543 
544 	setproctitle("running queue: %s", QueueDir);
545 
546 # ifdef LOG
547 	if (LogLevel > 69)
548 		syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
549 			QueueDir, getpid(), forkflag);
550 # endif /* LOG */
551 
552 	/*
553 	**  Release any resources used by the daemon code.
554 	*/
555 
556 # ifdef DAEMON
557 	clrdaemon();
558 # endif /* DAEMON */
559 
560 	/* force it to run expensive jobs */
561 	NoConnect = FALSE;
562 
563 	/*
564 	**  Create ourselves an envelope
565 	*/
566 
567 	CurEnv = &QueueEnvelope;
568 	e = newenvelope(&QueueEnvelope, CurEnv);
569 	e->e_flags = BlankEnvelope.e_flags;
570 
571 	/*
572 	**  Make sure the alias database is open.
573 	*/
574 
575 	initmaps(FALSE, e);
576 
577 	/*
578 	**  Start making passes through the queue.
579 	**	First, read and sort the entire queue.
580 	**	Then, process the work in that order.
581 	**		But if you take too long, start over.
582 	*/
583 
584 	/* order the existing work requests */
585 	njobs = orderq(FALSE);
586 
587 	/* process them once at a time */
588 	while (WorkQ != NULL)
589 	{
590 		WORK *w = WorkQ;
591 
592 		WorkQ = WorkQ->w_next;
593 
594 		/*
595 		**  Ignore jobs that are too expensive for the moment.
596 		*/
597 
598 		sequenceno++;
599 		if (shouldqueue(w->w_pri, w->w_ctime))
600 		{
601 			if (Verbose)
602 				printf("\nSkipping %s (sequence %d of %d)\n",
603 					w->w_name + 2, sequenceno, njobs);
604 		}
605 		else
606 		{
607 			pid_t pid;
608 			extern pid_t dowork();
609 
610 			if (Verbose)
611 				printf("\nRunning %s (sequence %d of %d)\n",
612 					w->w_name + 2, sequenceno, njobs);
613 			pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
614 			errno = 0;
615 			if (pid != 0)
616 				(void) waitfor(pid);
617 		}
618 		free(w->w_name);
619 		if (w->w_host)
620 			free(w->w_host);
621 		free((char *) w);
622 	}
623 
624 	/* exit without the usual cleanup */
625 	e->e_id = NULL;
626 	finis();
627 }
628 /*
629 **  ORDERQ -- order the work queue.
630 **
631 **	Parameters:
632 **		doall -- if set, include everything in the queue (even
633 **			the jobs that cannot be run because the load
634 **			average is too high).  Otherwise, exclude those
635 **			jobs.
636 **
637 **	Returns:
638 **		The number of request in the queue (not necessarily
639 **		the number of requests in WorkQ however).
640 **
641 **	Side Effects:
642 **		Sets WorkQ to the queue of available work, in order.
643 */
644 
645 # define NEED_P		001
646 # define NEED_T		002
647 # define NEED_R		004
648 # define NEED_S		010
649 
650 static WORK	*WorkList = NULL;
651 static int	WorkListSize = 0;
652 
653 int
654 orderq(doall)
655 	bool doall;
656 {
657 	register struct dirent *d;
658 	register WORK *w;
659 	DIR *f;
660 	register int i;
661 	int wn = -1;
662 	int wc;
663 
664 	if (tTd(41, 1))
665 	{
666 		printf("orderq:\n");
667 		if (QueueLimitId != NULL)
668 			printf("\tQueueLimitId = %s\n", QueueLimitId);
669 		if (QueueLimitSender != NULL)
670 			printf("\tQueueLimitSender = %s\n", QueueLimitSender);
671 		if (QueueLimitRecipient != NULL)
672 			printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
673 	}
674 
675 	/* clear out old WorkQ */
676 	for (w = WorkQ; w != NULL; )
677 	{
678 		register WORK *nw = w->w_next;
679 
680 		WorkQ = nw;
681 		free(w->w_name);
682 		if (w->w_host)
683 			free(w->w_host);
684 		free((char *) w);
685 		w = nw;
686 	}
687 
688 	/* open the queue directory */
689 	f = opendir(".");
690 	if (f == NULL)
691 	{
692 		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
693 		return (0);
694 	}
695 
696 	/*
697 	**  Read the work directory.
698 	*/
699 
700 	while ((d = readdir(f)) != NULL)
701 	{
702 		FILE *cf;
703 		register char *p;
704 		char lbuf[MAXNAME + 1];
705 		extern bool strcontainedin();
706 
707 		/* is this an interesting entry? */
708 		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
709 			continue;
710 
711 		if (QueueLimitId != NULL &&
712 		    !strcontainedin(QueueLimitId, d->d_name))
713 			continue;
714 
715 #ifdef PICKY_QF_NAME_CHECK
716 		/*
717 		**  Check queue name for plausibility.  This handles
718 		**  both old and new type ids.
719 		*/
720 
721 		p = d->d_name + 2;
722 		if (isupper(p[0]) && isupper(p[2]))
723 			p += 3;
724 		else if (isupper(p[1]))
725 			p += 2;
726 		else
727 			p = d->d_name;
728 		for (i = 0; isdigit(*p); p++)
729 			i++;
730 		if (i < 5 || *p != '\0')
731 		{
732 			if (Verbose)
733 				printf("orderq: bogus qf name %s\n", d->d_name);
734 # ifdef LOG
735 			if (LogLevel > 0)
736 				syslog(LOG_ALERT, "orderq: bogus qf name %s",
737 					d->d_name);
738 # endif
739 			if (strlen(d->d_name) > (SIZE_T) MAXNAME)
740 				d->d_name[MAXNAME] = '\0';
741 			strcpy(lbuf, d->d_name);
742 			lbuf[0] = 'Q';
743 			(void) rename(d->d_name, lbuf);
744 			continue;
745 		}
746 #endif
747 
748 		/* open control file (if not too many files) */
749 		if (++wn > MaxQueueRun && MaxQueueRun > 0)
750 		{
751 # ifdef LOG
752 			if (wn == MaxQueueRun + 1 && LogLevel > 0)
753 				syslog(LOG_ALERT, "WorkList for %s maxed out at %d",
754 						QueueDir, MaxQueueRun);
755 # endif
756 			continue;
757 		}
758 		if (wn >= WorkListSize)
759 		{
760 			extern void grow_wlist __P((void));
761 
762 			grow_wlist();
763 			if (wn >= WorkListSize)
764 				continue;
765 		}
766 
767 		cf = fopen(d->d_name, "r");
768 		if (cf == NULL)
769 		{
770 			/* this may be some random person sending hir msgs */
771 			/* syserr("orderq: cannot open %s", cbuf); */
772 			if (tTd(41, 2))
773 				printf("orderq: cannot open %s (%d)\n",
774 					d->d_name, errno);
775 			errno = 0;
776 			wn--;
777 			continue;
778 		}
779 		w = &WorkList[wn];
780 		w->w_name = newstr(d->d_name);
781 		w->w_host = NULL;
782 		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
783 
784 		/* make sure jobs in creation don't clog queue */
785 		w->w_pri = 0x7fffffff;
786 		w->w_ctime = 0;
787 
788 		/* extract useful information */
789 		i = NEED_P | NEED_T;
790 		if (QueueLimitSender != NULL)
791 			i |= NEED_S;
792 		if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
793 			i |= NEED_R;
794 		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
795 		{
796 			extern bool strcontainedin();
797 
798 			switch (lbuf[0])
799 			{
800 			  case 'P':
801 				w->w_pri = atol(&lbuf[1]);
802 				i &= ~NEED_P;
803 				break;
804 
805 			  case 'T':
806 				w->w_ctime = atol(&lbuf[1]);
807 				i &= ~NEED_T;
808 				break;
809 
810 			  case 'R':
811 				if (w->w_host == NULL &&
812 				    (p = strrchr(&lbuf[1], '@')) != NULL)
813 					w->w_host = newstr(&p[1]);
814 				if (QueueLimitRecipient == NULL ||
815 				    strcontainedin(QueueLimitRecipient, &lbuf[1]))
816 					i &= ~NEED_R;
817 				break;
818 
819 			  case 'S':
820 				if (QueueLimitSender != NULL &&
821 				    strcontainedin(QueueLimitSender, &lbuf[1]))
822 					i &= ~NEED_S;
823 				break;
824 			}
825 		}
826 		(void) fclose(cf);
827 
828 		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
829 		    bitset(NEED_R|NEED_S, i))
830 		{
831 			/* don't even bother sorting this job in */
832 			free(w->w_name);
833 			if (w->w_host)
834 				free(w->w_host);
835 			wn--;
836 		}
837 	}
838 	(void) closedir(f);
839 	wn++;
840 
841 	wc = min(wn, WorkListSize);
842 
843 	if (QueueSortOrder == QS_BYHOST)
844 	{
845 		extern workcmpf1();
846 		extern workcmpf2();
847 
848 		/*
849 		**  Sort the work directory for the first time,
850 		**  based on host name, lock status, and priority.
851 		*/
852 
853 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
854 
855 		/*
856 		**  If one message to host is locked, "lock" all messages
857 		**  to that host.
858 		*/
859 
860 		i = 0;
861 		while (i < wc)
862 		{
863 			if (!WorkList[i].w_lock)
864 			{
865 				i++;
866 				continue;
867 			}
868 			w = &WorkList[i];
869 			while (++i < wc)
870 			{
871 				if (WorkList[i].w_host == NULL &&
872 				    w->w_host == NULL)
873 					WorkList[i].w_lock = TRUE;
874 				else if (WorkList[i].w_host != NULL &&
875 					 w->w_host != NULL &&
876 					 strcmp(WorkList[i].w_host, w->w_host) == 0)
877 					WorkList[i].w_lock = TRUE;
878 				else
879 					break;
880 			}
881 		}
882 
883 		/*
884 		**  Sort the work directory for the second time,
885 		**  based on lock status, host name, and priority.
886 		*/
887 
888 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
889 	}
890 	else
891 	{
892 		extern workcmpf0();
893 
894 		/*
895 		**  Simple sort based on queue priority only.
896 		*/
897 
898 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
899 	}
900 
901 	/*
902 	**  Convert the work list into canonical form.
903 	**	Should be turning it into a list of envelopes here perhaps.
904 	*/
905 
906 	WorkQ = NULL;
907 	for (i = wc; --i >= 0; )
908 	{
909 		w = (WORK *) xalloc(sizeof *w);
910 		w->w_name = WorkList[i].w_name;
911 		w->w_host = WorkList[i].w_host;
912 		w->w_lock = WorkList[i].w_lock;
913 		w->w_pri = WorkList[i].w_pri;
914 		w->w_ctime = WorkList[i].w_ctime;
915 		w->w_next = WorkQ;
916 		WorkQ = w;
917 	}
918 	free(WorkList);
919 	WorkList = NULL;
920 
921 	if (tTd(40, 1))
922 	{
923 		for (w = WorkQ; w != NULL; w = w->w_next)
924 			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
925 	}
926 
927 	return (wn);
928 }
929 /*
930 **  GROW_WLIST -- make the work list larger
931 **
932 **	Parameters:
933 **		none.
934 **
935 **	Returns:
936 **		none.
937 **
938 **	Side Effects:
939 **		Adds another QUEUESEGSIZE entries to WorkList if possible.
940 **		It can fail if there isn't enough memory, so WorkListSize
941 **		should be checked again upon return.
942 */
943 
944 void
945 grow_wlist()
946 {
947 	if (tTd(41, 1))
948 		printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
949 	if (WorkList == NULL)
950 	{
951 		WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
952 		WorkListSize = QUEUESEGSIZE;
953 	}
954 	else
955 	{
956 		int newsize = WorkListSize + QUEUESEGSIZE;
957 		WORK *newlist = (WORK *) realloc((char *)WorkList,
958 					  (unsigned)sizeof(WORK) * (newsize + 1));
959 
960 		if (newlist != NULL)
961 		{
962 			WorkListSize = newsize;
963 			WorkList = newlist;
964 # ifdef LOG
965 			if (LogLevel > 1)
966 			{
967 				syslog(LOG_NOTICE, "grew WorkList for %s to %d",
968 						QueueDir, WorkListSize);
969 			}
970 		}
971 		else if (LogLevel > 0)
972 		{
973 			syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d",
974 					QueueDir, newsize);
975 # endif
976 		}
977 	}
978 	if (tTd(41, 1))
979 		printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
980 }
981 /*
982 **  WORKCMPF0 -- simple priority-only compare function.
983 **
984 **	Parameters:
985 **		a -- the first argument.
986 **		b -- the second argument.
987 **
988 **	Returns:
989 **		-1 if a < b
990 **		 0 if a == b
991 **		+1 if a > b
992 **
993 **	Side Effects:
994 **		none.
995 */
996 
997 int
998 workcmpf0(a, b)
999 	register WORK *a;
1000 	register WORK *b;
1001 {
1002 	long pa = a->w_pri;
1003 	long pb = b->w_pri;
1004 
1005 	if (pa == pb)
1006 		return 0;
1007 	else if (pa > pb)
1008 		return 1;
1009 	else
1010 		return -1;
1011 }
1012 /*
1013 **  WORKCMPF1 -- first compare function for ordering work based on host name.
1014 **
1015 **	Sorts on host name, lock status, and priority in that order.
1016 **
1017 **	Parameters:
1018 **		a -- the first argument.
1019 **		b -- the second argument.
1020 **
1021 **	Returns:
1022 **		<0 if a < b
1023 **		 0 if a == b
1024 **		>0 if a > b
1025 **
1026 **	Side Effects:
1027 **		none.
1028 */
1029 
1030 int
1031 workcmpf1(a, b)
1032 	register WORK *a;
1033 	register WORK *b;
1034 {
1035 	int i;
1036 
1037 	/* host name */
1038 	if (a->w_host != NULL && b->w_host == NULL)
1039 		return 1;
1040 	else if (a->w_host == NULL && b->w_host != NULL)
1041 		return -1;
1042 	if (a->w_host != NULL && b->w_host != NULL &&
1043 	    (i = strcmp(a->w_host, b->w_host)))
1044 		return i;
1045 
1046 	/* lock status */
1047 	if (a->w_lock != b->w_lock)
1048 		return b->w_lock - a->w_lock;
1049 
1050 	/* job priority */
1051 	return a->w_pri - b->w_pri;
1052 }
1053 /*
1054 **  WORKCMPF2 -- second compare function for ordering work based on host name.
1055 **
1056 **	Sorts on lock status, host name, and priority in that order.
1057 **
1058 **	Parameters:
1059 **		a -- the first argument.
1060 **		b -- the second argument.
1061 **
1062 **	Returns:
1063 **		<0 if a < b
1064 **		 0 if a == b
1065 **		>0 if a > b
1066 **
1067 **	Side Effects:
1068 **		none.
1069 */
1070 
1071 int
1072 workcmpf2(a, b)
1073 	register WORK *a;
1074 	register WORK *b;
1075 {
1076 	int i;
1077 
1078 	/* lock status */
1079 	if (a->w_lock != b->w_lock)
1080 		return a->w_lock - b->w_lock;
1081 
1082 	/* host name */
1083 	if (a->w_host != NULL && b->w_host == NULL)
1084 		return 1;
1085 	else if (a->w_host == NULL && b->w_host != NULL)
1086 		return -1;
1087 	if (a->w_host != NULL && b->w_host != NULL &&
1088 	    (i = strcmp(a->w_host, b->w_host)))
1089 		return i;
1090 
1091 	/* job priority */
1092 	return a->w_pri - b->w_pri;
1093 }
1094 /*
1095 **  DOWORK -- do a work request.
1096 **
1097 **	Parameters:
1098 **		id -- the ID of the job to run.
1099 **		forkflag -- if set, run this in background.
1100 **		requeueflag -- if set, reinstantiate the queue quickly.
1101 **			This is used when expanding aliases in the queue.
1102 **			If forkflag is also set, it doesn't wait for the
1103 **			child.
1104 **		e - the envelope in which to run it.
1105 **
1106 **	Returns:
1107 **		process id of process that is running the queue job.
1108 **
1109 **	Side Effects:
1110 **		The work request is satisfied if possible.
1111 */
1112 
1113 pid_t
1114 dowork(id, forkflag, requeueflag, e)
1115 	char *id;
1116 	bool forkflag;
1117 	bool requeueflag;
1118 	register ENVELOPE *e;
1119 {
1120 	register pid_t pid;
1121 	extern bool readqf();
1122 
1123 	if (tTd(40, 1))
1124 		printf("dowork(%s)\n", id);
1125 
1126 	/*
1127 	**  Fork for work.
1128 	*/
1129 
1130 	if (forkflag)
1131 	{
1132 		pid = fork();
1133 		if (pid < 0)
1134 		{
1135 			syserr("dowork: cannot fork");
1136 			return 0;
1137 		}
1138 		else if (pid > 0)
1139 		{
1140 			/* parent -- clean out connection cache */
1141 			mci_flush(FALSE, NULL);
1142 		}
1143 	}
1144 	else
1145 	{
1146 		pid = 0;
1147 	}
1148 
1149 	if (pid == 0)
1150 	{
1151 		/*
1152 		**  CHILD
1153 		**	Lock the control file to avoid duplicate deliveries.
1154 		**		Then run the file as though we had just read it.
1155 		**	We save an idea of the temporary name so we
1156 		**		can recover on interrupt.
1157 		*/
1158 
1159 		/* set basic modes, etc. */
1160 		(void) alarm(0);
1161 		clearenvelope(e, FALSE);
1162 		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1163 		e->e_errormode = EM_MAIL;
1164 		e->e_id = id;
1165 		GrabTo = UseErrorsTo = FALSE;
1166 		ExitStat = EX_OK;
1167 		if (forkflag)
1168 		{
1169 			disconnect(1, e);
1170 			OpMode = MD_DELIVER;
1171 		}
1172 # ifdef LOG
1173 		if (LogLevel > 76)
1174 			syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
1175 			       getpid());
1176 # endif /* LOG */
1177 
1178 		/* don't use the headers from sendmail.cf... */
1179 		e->e_header = NULL;
1180 
1181 		/* read the queue control file -- return if locked */
1182 		if (!readqf(e))
1183 		{
1184 			if (tTd(40, 4))
1185 				printf("readqf(%s) failed\n", e->e_id);
1186 			if (forkflag)
1187 				exit(EX_OK);
1188 			else
1189 				return 0;
1190 		}
1191 
1192 		e->e_flags |= EF_INQUEUE;
1193 
1194 		/* if this has been tried recently, let it be */
1195 		if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
1196 		{
1197 			char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
1198 
1199 			e->e_flags |= EF_KEEPQUEUE;
1200 			if (Verbose || tTd(40, 8))
1201 				printf("%s: too young (%s)\n",
1202 					e->e_id, howlong);
1203 #ifdef LOG
1204 			if (LogLevel > 19)
1205 				syslog(LOG_DEBUG, "%s: too young (%s)",
1206 					e->e_id, howlong);
1207 #endif
1208 		}
1209 		else
1210 		{
1211 			eatheader(e, requeueflag);
1212 
1213 			if (requeueflag)
1214 				queueup(e, TRUE, FALSE);
1215 
1216 			/* do the delivery */
1217 			sendall(e, SM_DELIVER);
1218 		}
1219 
1220 		/* finish up and exit */
1221 		if (forkflag)
1222 			finis();
1223 		else
1224 			dropenvelope(e);
1225 	}
1226 	e->e_id = NULL;
1227 	return pid;
1228 }
1229 /*
1230 **  READQF -- read queue file and set up environment.
1231 **
1232 **	Parameters:
1233 **		e -- the envelope of the job to run.
1234 **
1235 **	Returns:
1236 **		TRUE if it successfully read the queue file.
1237 **		FALSE otherwise.
1238 **
1239 **	Side Effects:
1240 **		The queue file is returned locked.
1241 */
1242 
1243 bool
1244 readqf(e)
1245 	register ENVELOPE *e;
1246 {
1247 	register FILE *qfp;
1248 	ADDRESS *ctladdr;
1249 	struct stat st;
1250 	char *bp;
1251 	int qfver = 0;
1252 	register char *p;
1253 	char *orcpt = NULL;
1254 	char qf[20];
1255 	char buf[MAXLINE];
1256 	extern ADDRESS *setctluser();
1257 	extern void loseqfile();
1258 
1259 	/*
1260 	**  Read and process the file.
1261 	*/
1262 
1263 	strcpy(qf, queuename(e, 'q'));
1264 	qfp = fopen(qf, "r+");
1265 	if (qfp == NULL)
1266 	{
1267 		if (tTd(40, 8))
1268 			printf("readqf(%s): fopen failure (%s)\n",
1269 				qf, errstring(errno));
1270 		if (errno != ENOENT)
1271 			syserr("readqf: no control file %s", qf);
1272 		return FALSE;
1273 	}
1274 
1275 	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1276 	{
1277 		/* being processed by another queuer */
1278 		if (Verbose || tTd(40, 8))
1279 			printf("%s: locked\n", e->e_id);
1280 # ifdef LOG
1281 		if (LogLevel > 19)
1282 			syslog(LOG_DEBUG, "%s: locked", e->e_id);
1283 # endif /* LOG */
1284 		(void) fclose(qfp);
1285 		return FALSE;
1286 	}
1287 
1288 	/*
1289 	**  Check the queue file for plausibility to avoid attacks.
1290 	*/
1291 
1292 	if (fstat(fileno(qfp), &st) < 0)
1293 	{
1294 		/* must have been being processed by someone else */
1295 		if (tTd(40, 8))
1296 			printf("readqf(%s): fstat failure (%s)\n",
1297 				qf, errstring(errno));
1298 		fclose(qfp);
1299 		return FALSE;
1300 	}
1301 
1302 	if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
1303 	{
1304 # ifdef LOG
1305 		if (LogLevel > 0)
1306 		{
1307 			syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
1308 				e->e_id, st.st_uid, st.st_mode);
1309 		}
1310 # endif /* LOG */
1311 		if (tTd(40, 8))
1312 			printf("readqf(%s): bogus file\n", qf);
1313 		loseqfile(e, "bogus file uid in mqueue");
1314 		fclose(qfp);
1315 		return FALSE;
1316 	}
1317 
1318 	if (st.st_size == 0)
1319 	{
1320 		/* must be a bogus file -- just remove it */
1321 		(void) unlink(qf);
1322 		fclose(qfp);
1323 		return FALSE;
1324 	}
1325 
1326 	if (st.st_nlink == 0)
1327 	{
1328 		/*
1329 		**  Race condition -- we got a file just as it was being
1330 		**  unlinked.  Just assume it is zero length.
1331 		*/
1332 
1333 		fclose(qfp);
1334 		return FALSE;
1335 	}
1336 
1337 	/* good file -- save this lock */
1338 	e->e_lockfp = qfp;
1339 
1340 	/* do basic system initialization */
1341 	initsys(e);
1342 	define('i', e->e_id, e);
1343 
1344 	LineNumber = 0;
1345 	e->e_flags |= EF_GLOBALERRS;
1346 	OpMode = MD_DELIVER;
1347 	ctladdr = NULL;
1348 	e->e_dfino = -1;
1349 	e->e_msgsize = -1;
1350 	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1351 	{
1352 		register char *p;
1353 		u_long qflags;
1354 		ADDRESS *q;
1355 
1356 		if (tTd(40, 4))
1357 			printf("+++++ %s\n", bp);
1358 		switch (bp[0])
1359 		{
1360 		  case 'V':		/* queue file version number */
1361 			qfver = atoi(&bp[1]);
1362 			if (qfver > QF_VERSION)
1363 			{
1364 				syserr("Version number in qf (%d) greater than max (%d)",
1365 					qfver, QF_VERSION);
1366 			}
1367 			break;
1368 
1369 		  case 'C':		/* specify controlling user */
1370 			ctladdr = setctluser(&bp[1]);
1371 			break;
1372 
1373 		  case 'Q':		/* original recipient */
1374 			orcpt = newstr(&bp[1]);
1375 			break;
1376 
1377 		  case 'R':		/* specify recipient */
1378 			p = bp;
1379 			qflags = 0;
1380 			if (qfver >= 1)
1381 			{
1382 				/* get flag bits */
1383 				while (*++p != '\0' && *p != ':')
1384 				{
1385 					switch (*p)
1386 					{
1387 					  case 'S':
1388 						qflags |= QPINGONSUCCESS;
1389 						break;
1390 
1391 					  case 'F':
1392 						qflags |= QPINGONFAILURE;
1393 						break;
1394 
1395 					  case 'D':
1396 						qflags |= QPINGONDELAY;
1397 						break;
1398 
1399 					  case 'P':
1400 						qflags |= QPRIMARY;
1401 						break;
1402 					}
1403 				}
1404 			}
1405 			else
1406 				qflags |= QPRIMARY;
1407 			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
1408 			if (q != NULL)
1409 			{
1410 				q->q_alias = ctladdr;
1411 				q->q_flags |= qflags;
1412 				q->q_orcpt = orcpt;
1413 				(void) recipient(q, &e->e_sendqueue, 0, e);
1414 			}
1415 			orcpt = NULL;
1416 			break;
1417 
1418 		  case 'E':		/* specify error recipient */
1419 			/* no longer used */
1420 			break;
1421 
1422 		  case 'H':		/* header */
1423 			(void) chompheader(&bp[1], FALSE, NULL, e);
1424 			break;
1425 
1426 		  case 'M':		/* message */
1427 			/* ignore this; we want a new message next time */
1428 			break;
1429 
1430 		  case 'S':		/* sender */
1431 			setsender(newstr(&bp[1]), e, NULL, TRUE);
1432 			break;
1433 
1434 		  case 'B':		/* body type */
1435 			e->e_bodytype = newstr(&bp[1]);
1436 			break;
1437 
1438 		  case 'D':		/* data file name */
1439 			/* obsolete -- ignore */
1440 			break;
1441 
1442 		  case 'T':		/* init time */
1443 			e->e_ctime = atol(&bp[1]);
1444 			break;
1445 
1446 		  case 'I':		/* data file's inode number */
1447 			if (e->e_dfino == -1)
1448 				e->e_dfino = atol(&buf[1]);
1449 			break;
1450 
1451 		  case 'K':		/* time of last deliver attempt */
1452 			e->e_dtime = atol(&buf[1]);
1453 			break;
1454 
1455 		  case 'N':		/* number of delivery attempts */
1456 			e->e_ntries = atoi(&buf[1]);
1457 			break;
1458 
1459 		  case 'P':		/* message priority */
1460 			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
1461 			break;
1462 
1463 		  case 'F':		/* flag bits */
1464 			for (p = &bp[1]; *p != '\0'; p++)
1465 			{
1466 				switch (*p)
1467 				{
1468 				  case 'w':	/* warning sent */
1469 					e->e_flags |= EF_WARNING;
1470 					break;
1471 
1472 				  case 'r':	/* response */
1473 					e->e_flags |= EF_RESPONSE;
1474 					break;
1475 
1476 				  case '8':	/* has 8 bit data */
1477 					e->e_flags |= EF_HAS8BIT;
1478 					break;
1479 				}
1480 			}
1481 			break;
1482 
1483 		  case 'Z':		/* original envelope id from ESMTP */
1484 			e->e_envid = newstr(&bp[1]);
1485 			break;
1486 
1487 		  case '$':		/* define macro */
1488 			define(bp[1], newstr(&bp[2]), e);
1489 			break;
1490 
1491 		  case '\0':		/* blank line; ignore */
1492 			break;
1493 
1494 		  default:
1495 			syserr("readqf: %s: line %d: bad line \"%s\"",
1496 				qf, LineNumber, bp);
1497 			fclose(qfp);
1498 			loseqfile(e, "unrecognized line");
1499 			return FALSE;
1500 		}
1501 
1502 		if (bp != buf)
1503 			free(bp);
1504 	}
1505 
1506 	/*
1507 	**  If we haven't read any lines, this queue file is empty.
1508 	**  Arrange to remove it without referencing any null pointers.
1509 	*/
1510 
1511 	if (LineNumber == 0)
1512 	{
1513 		errno = 0;
1514 		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1515 	}
1516 	else
1517 	{
1518 		/*
1519 		**  Arrange to read the data file.
1520 		*/
1521 
1522 		p = queuename(e, 'd');
1523 		e->e_dfp = fopen(p, "r");
1524 		if (e->e_dfp == NULL)
1525 		{
1526 			syserr("readqf: cannot open %s", p);
1527 		}
1528 		else
1529 		{
1530 			e->e_flags |= EF_HAS_DF;
1531 			if (fstat(fileno(e->e_dfp), &st) >= 0)
1532 			{
1533 				e->e_msgsize = st.st_size;
1534 				e->e_dfdev = st.st_dev;
1535 				e->e_dfino = st.st_ino;
1536 			}
1537 		}
1538 	}
1539 
1540 	return TRUE;
1541 }
1542 /*
1543 **  PRINTQUEUE -- print out a representation of the mail queue
1544 **
1545 **	Parameters:
1546 **		none.
1547 **
1548 **	Returns:
1549 **		none.
1550 **
1551 **	Side Effects:
1552 **		Prints a listing of the mail queue on the standard output.
1553 */
1554 
1555 void
1556 printqueue()
1557 {
1558 	register WORK *w;
1559 	FILE *f;
1560 	int nrequests;
1561 	char buf[MAXLINE];
1562 
1563 	/*
1564 	**  Check for permission to print the queue
1565 	*/
1566 
1567 	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
1568 	{
1569 		struct stat st;
1570 # ifdef NGROUPS
1571 		int n;
1572 		GIDSET_T gidset[NGROUPS];
1573 # endif
1574 
1575 		if (stat(QueueDir, &st) < 0)
1576 		{
1577 			syserr("Cannot stat %s", QueueDir);
1578 			return;
1579 		}
1580 # ifdef NGROUPS
1581 		n = getgroups(NGROUPS, gidset);
1582 		while (--n >= 0)
1583 		{
1584 			if (gidset[n] == st.st_gid)
1585 				break;
1586 		}
1587 		if (n < 0)
1588 # else
1589 		if (RealGid != st.st_gid)
1590 # endif
1591 		{
1592 			usrerr("510 You are not permitted to see the queue");
1593 			setstat(EX_NOPERM);
1594 			return;
1595 		}
1596 	}
1597 
1598 	/*
1599 	**  Read and order the queue.
1600 	*/
1601 
1602 	nrequests = orderq(TRUE);
1603 
1604 	/*
1605 	**  Print the work list that we have read.
1606 	*/
1607 
1608 	/* first see if there is anything */
1609 	if (nrequests <= 0)
1610 	{
1611 		printf("Mail queue is empty\n");
1612 		return;
1613 	}
1614 
1615 	CurrentLA = getla();	/* get load average */
1616 
1617 	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
1618 	if (nrequests > WorkListSize)
1619 		printf(", only %d printed", WorkListSize);
1620 	if (Verbose)
1621 		printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
1622 	else
1623 		printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
1624 	for (w = WorkQ; w != NULL; w = w->w_next)
1625 	{
1626 		struct stat st;
1627 		auto time_t submittime = 0;
1628 		long dfsize;
1629 		int flags = 0;
1630 		int qfver;
1631 		char statmsg[MAXLINE];
1632 		char bodytype[MAXNAME + 1];
1633 
1634 		printf("%8s", w->w_name + 2);
1635 		f = fopen(w->w_name, "r");
1636 		if (f == NULL)
1637 		{
1638 			printf(" (job completed)\n");
1639 			errno = 0;
1640 			continue;
1641 		}
1642 		w->w_name[0] = 'd';
1643 		if (stat(w->w_name, &st) >= 0)
1644 			dfsize = st.st_size;
1645 		else
1646 			dfsize = -1;
1647 		if (w->w_lock)
1648 			printf("*");
1649 		else if (shouldqueue(w->w_pri, w->w_ctime))
1650 			printf("X");
1651 		else
1652 			printf(" ");
1653 		errno = 0;
1654 
1655 		statmsg[0] = bodytype[0] = '\0';
1656 		qfver = 0;
1657 		while (fgets(buf, sizeof buf, f) != NULL)
1658 		{
1659 			register int i;
1660 			register char *p;
1661 
1662 			fixcrlf(buf, TRUE);
1663 			switch (buf[0])
1664 			{
1665 			  case 'V':	/* queue file version */
1666 				qfver = atoi(&buf[1]);
1667 				break;
1668 
1669 			  case 'M':	/* error message */
1670 				if ((i = strlen(&buf[1])) >= sizeof statmsg)
1671 					i = sizeof statmsg - 1;
1672 				bcopy(&buf[1], statmsg, i);
1673 				statmsg[i] = '\0';
1674 				break;
1675 
1676 			  case 'B':	/* body type */
1677 				if ((i = strlen(&buf[1])) >= sizeof bodytype)
1678 					i = sizeof bodytype - 1;
1679 				bcopy(&buf[1], bodytype, i);
1680 				bodytype[i] = '\0';
1681 				break;
1682 
1683 			  case 'S':	/* sender name */
1684 				if (Verbose)
1685 					printf("%8ld %10ld%c%.12s %.38s",
1686 					    dfsize,
1687 					    w->w_pri,
1688 					    bitset(EF_WARNING, flags) ? '+' : ' ',
1689 					    ctime(&submittime) + 4,
1690 					    &buf[1]);
1691 				else
1692 					printf("%8ld %.16s %.45s", dfsize,
1693 					    ctime(&submittime), &buf[1]);
1694 				if (statmsg[0] != '\0' || bodytype[0] != '\0')
1695 				{
1696 					printf("\n    %10.10s", bodytype);
1697 					if (statmsg[0] != '\0')
1698 						printf("   (%.60s)", statmsg);
1699 				}
1700 				break;
1701 
1702 			  case 'C':	/* controlling user */
1703 				if (Verbose)
1704 					printf("\n\t\t\t\t      (---%.34s---)",
1705 						&buf[1]);
1706 				break;
1707 
1708 			  case 'R':	/* recipient name */
1709 				p = &buf[1];
1710 				if (qfver >= 1)
1711 				{
1712 					p = strchr(p, ':');
1713 					if (p == NULL)
1714 						break;
1715 					p++;
1716 				}
1717 				if (Verbose)
1718 					printf("\n\t\t\t\t\t  %.38s", p);
1719 				else
1720 					printf("\n\t\t\t\t   %.45s", p);
1721 				break;
1722 
1723 			  case 'T':	/* creation time */
1724 				submittime = atol(&buf[1]);
1725 				break;
1726 
1727 			  case 'F':	/* flag bits */
1728 				for (p = &buf[1]; *p != '\0'; p++)
1729 				{
1730 					switch (*p)
1731 					{
1732 					  case 'w':
1733 						flags |= EF_WARNING;
1734 						break;
1735 					}
1736 				}
1737 			}
1738 		}
1739 		if (submittime == (time_t) 0)
1740 			printf(" (no control file)");
1741 		printf("\n");
1742 		(void) fclose(f);
1743 	}
1744 }
1745 
1746 # endif /* QUEUE */
1747 /*
1748 **  QUEUENAME -- build a file name in the queue directory for this envelope.
1749 **
1750 **	Assigns an id code if one does not already exist.
1751 **	This code is very careful to avoid trashing existing files
1752 **	under any circumstances.
1753 **
1754 **	Parameters:
1755 **		e -- envelope to build it in/from.
1756 **		type -- the file type, used as the first character
1757 **			of the file name.
1758 **
1759 **	Returns:
1760 **		a pointer to the new file name (in a static buffer).
1761 **
1762 **	Side Effects:
1763 **		If no id code is already assigned, queuename will
1764 **		assign an id code, create a qf file, and leave a
1765 **		locked, open-for-write file pointer in the envelope.
1766 */
1767 
1768 char *
1769 queuename(e, type)
1770 	register ENVELOPE *e;
1771 	int type;
1772 {
1773 	static int pid = -1;
1774 	static char c0;
1775 	static char c1;
1776 	static char c2;
1777 	time_t now;
1778 	struct tm *tm;
1779 	static char buf[MAXNAME + 1];
1780 
1781 	if (e->e_id == NULL)
1782 	{
1783 		char qf[20];
1784 
1785 		/* find a unique id */
1786 		if (pid != getpid())
1787 		{
1788 			/* new process -- start back at "AA" */
1789 			pid = getpid();
1790 			now = curtime();
1791 			tm = localtime(&now);
1792 			c0 = 'A' + tm->tm_hour;
1793 			c1 = 'A';
1794 			c2 = 'A' - 1;
1795 		}
1796 		(void) sprintf(qf, "qf%cAA%05d", c0, pid);
1797 
1798 		while (c1 < '~' || c2 < 'Z')
1799 		{
1800 			int i;
1801 
1802 			if (c2 >= 'Z')
1803 			{
1804 				c1++;
1805 				c2 = 'A' - 1;
1806 			}
1807 			qf[3] = c1;
1808 			qf[4] = ++c2;
1809 			if (tTd(7, 20))
1810 				printf("queuename: trying \"%s\"\n", qf);
1811 
1812 			i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
1813 			if (i < 0)
1814 			{
1815 				if (errno == EEXIST)
1816 					continue;
1817 				syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1818 					qf, QueueDir, geteuid());
1819 				exit(EX_UNAVAILABLE);
1820 			}
1821 			if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
1822 			{
1823 				e->e_lockfp = fdopen(i, "w");
1824 				break;
1825 			}
1826 
1827 			/* a reader got the file; abandon it and try again */
1828 			(void) close(i);
1829 		}
1830 		if (c1 >= '~' && c2 >= 'Z')
1831 		{
1832 			syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1833 				qf, QueueDir, geteuid());
1834 			exit(EX_OSERR);
1835 		}
1836 		e->e_id = newstr(&qf[2]);
1837 		define('i', e->e_id, e);
1838 		if (tTd(7, 1))
1839 			printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1840 		if (tTd(7, 9))
1841 		{
1842 			printf("  lockfd=");
1843 			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1844 		}
1845 # ifdef LOG
1846 		if (LogLevel > 93)
1847 			syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
1848 # endif /* LOG */
1849 	}
1850 
1851 	if (type == '\0')
1852 		return (NULL);
1853 	(void) sprintf(buf, "%cf%s", type, e->e_id);
1854 	if (tTd(7, 2))
1855 		printf("queuename: %s\n", buf);
1856 	return (buf);
1857 }
1858 /*
1859 **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1860 **
1861 **	Parameters:
1862 **		e -- the envelope to unlock.
1863 **
1864 **	Returns:
1865 **		none
1866 **
1867 **	Side Effects:
1868 **		unlocks the queue for `e'.
1869 */
1870 
1871 void
1872 unlockqueue(e)
1873 	ENVELOPE *e;
1874 {
1875 	if (tTd(51, 4))
1876 		printf("unlockqueue(%s)\n", e->e_id);
1877 
1878 	/* if there is a lock file in the envelope, close it */
1879 	if (e->e_lockfp != NULL)
1880 		xfclose(e->e_lockfp, "unlockqueue", e->e_id);
1881 	e->e_lockfp = NULL;
1882 
1883 	/* don't create a queue id if we don't already have one */
1884 	if (e->e_id == NULL)
1885 		return;
1886 
1887 	/* remove the transcript */
1888 # ifdef LOG
1889 	if (LogLevel > 87)
1890 		syslog(LOG_DEBUG, "%s: unlock", e->e_id);
1891 # endif /* LOG */
1892 	if (!tTd(51, 104))
1893 		xunlink(queuename(e, 'x'));
1894 
1895 }
1896 /*
1897 **  SETCTLUSER -- create a controlling address
1898 **
1899 **	Create a fake "address" given only a local login name; this is
1900 **	used as a "controlling user" for future recipient addresses.
1901 **
1902 **	Parameters:
1903 **		user -- the user name of the controlling user.
1904 **
1905 **	Returns:
1906 **		An address descriptor for the controlling user.
1907 **
1908 **	Side Effects:
1909 **		none.
1910 */
1911 
1912 ADDRESS *
1913 setctluser(user)
1914 	char *user;
1915 {
1916 	register ADDRESS *a;
1917 	struct passwd *pw;
1918 	char *p;
1919 
1920 	/*
1921 	**  See if this clears our concept of controlling user.
1922 	*/
1923 
1924 	if (user == NULL || *user == '\0')
1925 		return NULL;
1926 
1927 	/*
1928 	**  Set up addr fields for controlling user.
1929 	*/
1930 
1931 	a = (ADDRESS *) xalloc(sizeof *a);
1932 	bzero((char *) a, sizeof *a);
1933 
1934 	p = strchr(user, ':');
1935 	if (p != NULL)
1936 		*p++ = '\0';
1937 	if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL)
1938 	{
1939 		if (strcmp(pw->pw_dir, "/") == 0)
1940 			a->q_home = "";
1941 		else
1942 			a->q_home = newstr(pw->pw_dir);
1943 		a->q_uid = pw->pw_uid;
1944 		a->q_gid = pw->pw_gid;
1945 		a->q_flags |= QGOODUID;
1946 	}
1947 
1948 	if (*user != '\0')
1949 		a->q_user = newstr(user);
1950 	else if (p != NULL)
1951 		a->q_user = newstr(p);
1952 	else
1953 		a->q_user = newstr(DefUser);
1954 
1955 	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr"  */
1956 	a->q_mailer = LocalMailer;
1957 	if (p == NULL)
1958 		a->q_paddr = a->q_user;
1959 	else
1960 		a->q_paddr = newstr(p);
1961 	return a;
1962 }
1963 /*
1964 **  LOSEQFILE -- save the qf as Qf and try to let someone know
1965 **
1966 **	Parameters:
1967 **		e -- the envelope (e->e_id will be used).
1968 **		why -- reported to whomever can hear.
1969 **
1970 **	Returns:
1971 **		none.
1972 */
1973 
1974 void
1975 loseqfile(e, why)
1976 	register ENVELOPE *e;
1977 	char *why;
1978 {
1979 	char *p;
1980 	char buf[40];
1981 
1982 	if (e == NULL || e->e_id == NULL)
1983 		return;
1984 	if (strlen(e->e_id) > sizeof buf - 4)
1985 		return;
1986 	strcpy(buf, queuename(e, 'q'));
1987 	p = queuename(e, 'Q');
1988 	if (rename(buf, p) < 0)
1989 		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
1990 #ifdef LOG
1991 	else if (LogLevel > 0)
1992 		syslog(LOG_ALERT, "Losing %s: %s", buf, why);
1993 #endif
1994 }
1995