xref: /original-bsd/usr.sbin/sendmail/src/queue.c (revision c8089215)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * 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	5.32 (Berkeley) 03/12/91 (with queueing)";
14 #else
15 static char sccsid[] = "@(#)queue.c	5.32 (Berkeley) 03/12/91 (without queueing)";
16 #endif
17 #endif /* not lint */
18 
19 # include <sys/stat.h>
20 # include <sys/dir.h>
21 # include <sys/file.h>
22 # include <signal.h>
23 # include <errno.h>
24 # include <pwd.h>
25 
26 # ifdef QUEUE
27 
28 /*
29 **  Work queue.
30 */
31 
32 struct work
33 {
34 	char		*w_name;	/* name of control file */
35 	long		w_pri;		/* priority of message, see below */
36 	time_t		w_ctime;	/* creation time of message */
37 	struct work	*w_next;	/* next in queue */
38 };
39 
40 typedef struct work	WORK;
41 extern int la;
42 
43 WORK	*WorkQ;			/* queue of things to be done */
44 /*
45 **  QUEUEUP -- queue a message up for future transmission.
46 **
47 **	Parameters:
48 **		e -- the envelope to queue up.
49 **		queueall -- if TRUE, queue all addresses, rather than
50 **			just those with the QQUEUEUP flag set.
51 **		announce -- if TRUE, tell when you are queueing up.
52 **
53 **	Returns:
54 **		locked FILE* to q file
55 **
56 **	Side Effects:
57 **		The current request are saved in a control file.
58 */
59 
60 FILE *
61 queueup(e, queueall, announce)
62 	register ENVELOPE *e;
63 	bool queueall;
64 	bool announce;
65 {
66 	char *qf;
67 	char buf[MAXLINE], tf[MAXLINE];
68 	register FILE *tfp;
69 	register HDR *h;
70 	register ADDRESS *q;
71 	MAILER nullmailer;
72 	int fd, ret;
73 
74 	/*
75 	**  Create control file.
76 	*/
77 
78 	do {
79 		strcpy(tf, queuename(e, 't'));
80 		fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
81 		if (fd < 0) {
82 			if ( errno != EEXIST) {
83 				syserr("queueup: cannot create temp file %s",
84 					tf);
85 				return NULL;
86 			}
87 		} else {
88 			if (flock(fd, LOCK_EX|LOCK_NB) < 0) {
89 				if (errno != EWOULDBLOCK)
90 					syserr("cannot flock(%s)", tf);
91 				close(fd);
92 				fd = -1;
93 			}
94 		}
95 	} while (fd < 0);
96 
97 	tfp = fdopen(fd, "w");
98 
99 	if (tTd(40, 1))
100 		printf("queueing %s\n", e->e_id);
101 
102 	/*
103 	**  If there is no data file yet, create one.
104 	*/
105 
106 	if (e->e_df == NULL)
107 	{
108 		register FILE *dfp;
109 		extern putbody();
110 
111 		e->e_df = newstr(queuename(e, 'd'));
112 		fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
113 		if (fd < 0)
114 		{
115 			syserr("queueup: cannot create %s", e->e_df);
116 			(void) fclose(tfp);
117 			return NULL;
118 		}
119 		dfp = fdopen(fd, "w");
120 		(*e->e_putbody)(dfp, ProgMailer, e);
121 		(void) fclose(dfp);
122 		e->e_putbody = putbody;
123 	}
124 
125 	/*
126 	**  Output future work requests.
127 	**	Priority and creation time should be first, since
128 	**	they are required by orderq.
129 	*/
130 
131 	/* output message priority */
132 	fprintf(tfp, "P%ld\n", e->e_msgpriority);
133 
134 	/* output creation time */
135 	fprintf(tfp, "T%ld\n", e->e_ctime);
136 
137 	/* output name of data file */
138 	fprintf(tfp, "D%s\n", e->e_df);
139 
140 	/* message from envelope, if it exists */
141 	if (e->e_message != NULL)
142 		fprintf(tfp, "M%s\n", e->e_message);
143 
144 	/* output name of sender */
145 	fprintf(tfp, "S%s\n", e->e_from.q_paddr);
146 
147 	/* output list of recipient addresses */
148 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
149 	{
150 		if (queueall ? !bitset(QDONTSEND|QSENT, q->q_flags) :
151 			       bitset(QQUEUEUP, q->q_flags))
152 		{
153 			char *ctluser, *getctluser();
154 
155 			if ((ctluser = getctluser(q)) != NULL)
156 				fprintf(tfp, "C%s\n", ctluser);
157 			fprintf(tfp, "R%s\n", q->q_paddr);
158 			if (announce)
159 			{
160 				e->e_to = q->q_paddr;
161 				message(Arpa_Info, "queued");
162 				if (LogLevel > 4)
163 					logdelivery("queued");
164 				e->e_to = NULL;
165 			}
166 			if (tTd(40, 1))
167 			{
168 				printf("queueing ");
169 				printaddr(q, FALSE);
170 			}
171 		}
172 	}
173 
174 	/* output list of error recipients */
175 	for (q = e->e_errorqueue; q != NULL; q = q->q_next)
176 	{
177 		if (!bitset(QDONTSEND, q->q_flags))
178 		{
179 			char *ctluser, *getctluser();
180 
181 			if ((ctluser = getctluser(q)) != NULL)
182 				fprintf(tfp, "C%s\n", ctluser);
183 			fprintf(tfp, "E%s\n", q->q_paddr);
184 		}
185 	}
186 
187 	/*
188 	**  Output headers for this message.
189 	**	Expand macros completely here.  Queue run will deal with
190 	**	everything as absolute headers.
191 	**		All headers that must be relative to the recipient
192 	**		can be cracked later.
193 	**	We set up a "null mailer" -- i.e., a mailer that will have
194 	**	no effect on the addresses as they are output.
195 	*/
196 
197 	bzero((char *) &nullmailer, sizeof nullmailer);
198 	nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;
199 	nullmailer.m_eol = "\n";
200 
201 	define('g', "\001f", e);
202 	for (h = e->e_header; h != NULL; h = h->h_link)
203 	{
204 		extern bool bitzerop();
205 
206 		/* don't output null headers */
207 		if (h->h_value == NULL || h->h_value[0] == '\0')
208 			continue;
209 
210 		/* don't output resent headers on non-resent messages */
211 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
212 			continue;
213 
214 		/* output this header */
215 		fprintf(tfp, "H");
216 
217 		/* if conditional, output the set of conditions */
218 		if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
219 		{
220 			int j;
221 
222 			(void) putc('?', tfp);
223 			for (j = '\0'; j <= '\177'; j++)
224 				if (bitnset(j, h->h_mflags))
225 					(void) putc(j, tfp);
226 			(void) putc('?', tfp);
227 		}
228 
229 		/* output the header: expand macros, convert addresses */
230 		if (bitset(H_DEFAULT, h->h_flags))
231 		{
232 			(void) expand(h->h_value, buf, &buf[sizeof buf], e);
233 			fprintf(tfp, "%s: %s\n", h->h_field, buf);
234 		}
235 		else if (bitset(H_FROM|H_RCPT, h->h_flags))
236 		{
237 			commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
238 				 &nullmailer);
239 		}
240 		else
241 			fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
242 	}
243 
244 	/*
245 	**  Clean up.
246 	*/
247 
248 	qf = queuename(e, 'q');
249 	if (rename(tf, qf) < 0)
250 		syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df);
251 	errno = 0;
252 
253 # ifdef LOG
254 	/* save log info */
255 	if (LogLevel > 15)
256 		syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
257 # endif LOG
258 	fflush(tfp);
259 	return tfp;
260 }
261 /*
262 **  RUNQUEUE -- run the jobs in the queue.
263 **
264 **	Gets the stuff out of the queue in some presumably logical
265 **	order and processes them.
266 **
267 **	Parameters:
268 **		forkflag -- TRUE if the queue scanning should be done in
269 **			a child process.  We double-fork so it is not our
270 **			child and we don't have to clean up after it.
271 **
272 **	Returns:
273 **		none.
274 **
275 **	Side Effects:
276 **		runs things in the mail queue.
277 */
278 
279 runqueue(forkflag)
280 	bool forkflag;
281 {
282 	extern bool shouldqueue();
283 
284 	/*
285 	**  If no work will ever be selected, don't even bother reading
286 	**  the queue.
287 	*/
288 
289 	la = getla();	/* get load average */
290 
291 	if (shouldqueue(-100000000L))
292 	{
293 		if (Verbose)
294 			printf("Skipping queue run -- load average too high\n");
295 
296 		if (forkflag)
297 			return;
298 		finis();
299 	}
300 
301 	/*
302 	**  See if we want to go off and do other useful work.
303 	*/
304 
305 	if (forkflag)
306 	{
307 		int pid;
308 
309 		pid = dofork();
310 		if (pid != 0)
311 		{
312 			extern void reapchild();
313 
314 			/* parent -- pick up intermediate zombie */
315 #ifndef SIGCHLD
316 			(void) waitfor(pid);
317 #else SIGCHLD
318 			(void) signal(SIGCHLD, reapchild);
319 #endif SIGCHLD
320 			if (QueueIntvl != 0)
321 				(void) setevent(QueueIntvl, runqueue, TRUE);
322 			return;
323 		}
324 		/* child -- double fork */
325 #ifndef SIGCHLD
326 		if (fork() != 0)
327 			exit(EX_OK);
328 #else SIGCHLD
329 		(void) signal(SIGCHLD, SIG_DFL);
330 #endif SIGCHLD
331 	}
332 
333 	setproctitle("running queue: %s", QueueDir);
334 
335 # ifdef LOG
336 	if (LogLevel > 11)
337 		syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
338 # endif LOG
339 
340 	/*
341 	**  Release any resources used by the daemon code.
342 	*/
343 
344 # ifdef DAEMON
345 	clrdaemon();
346 # endif DAEMON
347 
348 	/*
349 	**  Make sure the alias database is open.
350 	*/
351 
352 	initaliases(AliasFile, FALSE);
353 
354 	/*
355 	**  Start making passes through the queue.
356 	**	First, read and sort the entire queue.
357 	**	Then, process the work in that order.
358 	**		But if you take too long, start over.
359 	*/
360 
361 	/* order the existing work requests */
362 	(void) orderq(FALSE);
363 
364 	/* process them once at a time */
365 	while (WorkQ != NULL)
366 	{
367 		WORK *w = WorkQ;
368 
369 		WorkQ = WorkQ->w_next;
370 		dowork(w);
371 		free(w->w_name);
372 		free((char *) w);
373 	}
374 
375 	/* exit without the usual cleanup */
376 	exit(ExitStat);
377 }
378 /*
379 **  ORDERQ -- order the work queue.
380 **
381 **	Parameters:
382 **		doall -- if set, include everything in the queue (even
383 **			the jobs that cannot be run because the load
384 **			average is too high).  Otherwise, exclude those
385 **			jobs.
386 **
387 **	Returns:
388 **		The number of request in the queue (not necessarily
389 **		the number of requests in WorkQ however).
390 **
391 **	Side Effects:
392 **		Sets WorkQ to the queue of available work, in order.
393 */
394 
395 # define NEED_P		001
396 # define NEED_T		002
397 
398 orderq(doall)
399 	bool doall;
400 {
401 	register struct direct *d;
402 	register WORK *w;
403 	DIR *f;
404 	register int i;
405 	WORK wlist[QUEUESIZE+1];
406 	int wn = -1;
407 	extern workcmpf();
408 
409 	/* clear out old WorkQ */
410 	for (w = WorkQ; w != NULL; )
411 	{
412 		register WORK *nw = w->w_next;
413 
414 		WorkQ = nw;
415 		free(w->w_name);
416 		free((char *) w);
417 		w = nw;
418 	}
419 
420 	/* open the queue directory */
421 	f = opendir(".");
422 	if (f == NULL)
423 	{
424 		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
425 		return (0);
426 	}
427 
428 	/*
429 	**  Read the work directory.
430 	*/
431 
432 	while ((d = readdir(f)) != NULL)
433 	{
434 		FILE *cf;
435 		char lbuf[MAXNAME];
436 
437 		/* is this an interesting entry? */
438 		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
439 			continue;
440 
441 		/* yes -- open control file (if not too many files) */
442 		if (++wn >= QUEUESIZE)
443 			continue;
444 		cf = fopen(d->d_name, "r");
445 		if (cf == NULL)
446 		{
447 			/* this may be some random person sending hir msgs */
448 			/* syserr("orderq: cannot open %s", cbuf); */
449 			if (tTd(41, 2))
450 				printf("orderq: cannot open %s (%d)\n",
451 					d->d_name, errno);
452 			errno = 0;
453 			wn--;
454 			continue;
455 		}
456 		w = &wlist[wn];
457 		w->w_name = newstr(d->d_name);
458 
459 		/* make sure jobs in creation don't clog queue */
460 		w->w_pri = 0x7fffffff;
461 		w->w_ctime = 0;
462 
463 		/* extract useful information */
464 		i = NEED_P | NEED_T;
465 		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
466 		{
467 			extern long atol();
468 
469 			switch (lbuf[0])
470 			{
471 			  case 'P':
472 				w->w_pri = atol(&lbuf[1]);
473 				i &= ~NEED_P;
474 				break;
475 
476 			  case 'T':
477 				w->w_ctime = atol(&lbuf[1]);
478 				i &= ~NEED_T;
479 				break;
480 			}
481 		}
482 		(void) fclose(cf);
483 
484 		if (!doall && shouldqueue(w->w_pri))
485 		{
486 			/* don't even bother sorting this job in */
487 			wn--;
488 		}
489 	}
490 	(void) closedir(f);
491 	wn++;
492 
493 	/*
494 	**  Sort the work directory.
495 	*/
496 
497 	qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
498 
499 	/*
500 	**  Convert the work list into canonical form.
501 	**	Should be turning it into a list of envelopes here perhaps.
502 	*/
503 
504 	WorkQ = NULL;
505 	for (i = min(wn, QUEUESIZE); --i >= 0; )
506 	{
507 		w = (WORK *) xalloc(sizeof *w);
508 		w->w_name = wlist[i].w_name;
509 		w->w_pri = wlist[i].w_pri;
510 		w->w_ctime = wlist[i].w_ctime;
511 		w->w_next = WorkQ;
512 		WorkQ = w;
513 	}
514 
515 	if (tTd(40, 1))
516 	{
517 		for (w = WorkQ; w != NULL; w = w->w_next)
518 			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
519 	}
520 
521 	return (wn);
522 }
523 /*
524 **  WORKCMPF -- compare function for ordering work.
525 **
526 **	Parameters:
527 **		a -- the first argument.
528 **		b -- the second argument.
529 **
530 **	Returns:
531 **		-1 if a < b
532 **		 0 if a == b
533 **		+1 if a > b
534 **
535 **	Side Effects:
536 **		none.
537 */
538 
539 workcmpf(a, b)
540 	register WORK *a;
541 	register WORK *b;
542 {
543 	long pa = a->w_pri + a->w_ctime;
544 	long pb = b->w_pri + b->w_ctime;
545 
546 	if (pa == pb)
547 		return (0);
548 	else if (pa > pb)
549 		return (1);
550 	else
551 		return (-1);
552 }
553 /*
554 **  DOWORK -- do a work request.
555 **
556 **	Parameters:
557 **		w -- the work request to be satisfied.
558 **
559 **	Returns:
560 **		none.
561 **
562 **	Side Effects:
563 **		The work request is satisfied if possible.
564 */
565 
566 dowork(w)
567 	register WORK *w;
568 {
569 	register int i;
570 	extern bool shouldqueue();
571 
572 	if (tTd(40, 1))
573 		printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
574 
575 	/*
576 	**  Ignore jobs that are too expensive for the moment.
577 	*/
578 
579 	if (shouldqueue(w->w_pri))
580 	{
581 		if (Verbose)
582 			printf("\nSkipping %s\n", w->w_name + 2);
583 		return;
584 	}
585 
586 	/*
587 	**  Fork for work.
588 	*/
589 
590 	if (ForkQueueRuns)
591 	{
592 		i = fork();
593 		if (i < 0)
594 		{
595 			syserr("dowork: cannot fork");
596 			return;
597 		}
598 	}
599 	else
600 	{
601 		i = 0;
602 	}
603 
604 	if (i == 0)
605 	{
606 		FILE *qflock, *readqf();
607 		/*
608 		**  CHILD
609 		**	Lock the control file to avoid duplicate deliveries.
610 		**		Then run the file as though we had just read it.
611 		**	We save an idea of the temporary name so we
612 		**		can recover on interrupt.
613 		*/
614 
615 		/* set basic modes, etc. */
616 		(void) alarm(0);
617 		clearenvelope(CurEnv, FALSE);
618 		QueueRun = TRUE;
619 		ErrorMode = EM_MAIL;
620 		CurEnv->e_id = &w->w_name[2];
621 # ifdef LOG
622 		if (LogLevel > 11)
623 			syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
624 			       getpid());
625 # endif LOG
626 
627 		/* don't use the headers from sendmail.cf... */
628 		CurEnv->e_header = NULL;
629 
630 		/* read the queue control file */
631 		/*  and lock the control file during processing */
632 		if ((qflock=readqf(CurEnv, TRUE)) == NULL)
633 		{
634 			if (ForkQueueRuns)
635 				exit(EX_OK);
636 			else
637 				return;
638 		}
639 
640 		CurEnv->e_flags |= EF_INQUEUE;
641 		eatheader(CurEnv);
642 
643 		/* do the delivery */
644 		if (!bitset(EF_FATALERRS, CurEnv->e_flags))
645 			sendall(CurEnv, SM_DELIVER);
646 
647 		/* finish up and exit */
648 		if (ForkQueueRuns)
649 			finis();
650 		else
651 			dropenvelope(CurEnv);
652 		fclose(qflock);
653 	}
654 	else
655 	{
656 		/*
657 		**  Parent -- pick up results.
658 		*/
659 
660 		errno = 0;
661 		(void) waitfor(i);
662 	}
663 }
664 /*
665 **  READQF -- read queue file and set up environment.
666 **
667 **	Parameters:
668 **		e -- the envelope of the job to run.
669 **		full -- if set, read in all information.  Otherwise just
670 **			read in info needed for a queue print.
671 **
672 **	Returns:
673 **		FILE * pointing to flock()ed fd so it can be closed
674 **		after the mail is delivered
675 **
676 **	Side Effects:
677 **		cf is read and created as the current job, as though
678 **		we had been invoked by argument.
679 */
680 
681 FILE *
682 readqf(e, full)
683 	register ENVELOPE *e;
684 	bool full;
685 {
686 	char *qf;
687 	register FILE *qfp;
688 	char buf[MAXFIELD];
689 	extern char *fgetfolded();
690 	extern long atol();
691 	int gotctluser = 0;
692 	int fd;
693 
694 	/*
695 	**  Read and process the file.
696 	*/
697 
698 	qf = queuename(e, 'q');
699 	qfp = fopen(qf, "r");
700 	if (qfp == NULL)
701 	{
702 		if (errno != ENOENT)
703 			syserr("readqf: no control file %s", qf);
704 		return NULL;
705 	}
706 
707 	if (flock(fileno(qfp), LOCK_EX|LOCK_NB) < 0)
708 	{
709 # ifdef LOG
710 		/* being processed by another queuer */
711 		if (Verbose)
712 			printf("%s: locked\n", CurEnv->e_id);
713 # endif LOG
714 		(void) fclose(qfp);
715 		return NULL;
716 	}
717 
718 	/* do basic system initialization */
719 	initsys();
720 
721 	FileName = qf;
722 	LineNumber = 0;
723 	if (Verbose && full)
724 		printf("\nRunning %s\n", e->e_id);
725 	while (fgetfolded(buf, sizeof buf, qfp) != NULL)
726 	{
727 		if (tTd(40, 4))
728 			printf("+++++ %s\n", buf);
729 		switch (buf[0])
730 		{
731 		  case 'C':		/* specify controlling user */
732 			setctluser(&buf[1]);
733 			gotctluser = 1;
734 			break;
735 
736 		  case 'R':		/* specify recipient */
737 			sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue);
738 			break;
739 
740 		  case 'E':		/* specify error recipient */
741 			sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue);
742 			break;
743 
744 		  case 'H':		/* header */
745 			if (full)
746 				(void) chompheader(&buf[1], FALSE);
747 			break;
748 
749 		  case 'M':		/* message */
750 			e->e_message = newstr(&buf[1]);
751 			break;
752 
753 		  case 'S':		/* sender */
754 			setsender(newstr(&buf[1]));
755 			break;
756 
757 		  case 'D':		/* data file name */
758 			if (!full)
759 				break;
760 			e->e_df = newstr(&buf[1]);
761 			e->e_dfp = fopen(e->e_df, "r");
762 			if (e->e_dfp == NULL)
763 				syserr("readqf: cannot open %s", e->e_df);
764 			break;
765 
766 		  case 'T':		/* init time */
767 			e->e_ctime = atol(&buf[1]);
768 			break;
769 
770 		  case 'P':		/* message priority */
771 			e->e_msgpriority = atol(&buf[1]) + WkTimeFact;
772 			break;
773 
774 		  case '\0':		/* blank line; ignore */
775 			break;
776 
777 		  default:
778 			syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
779 				LineNumber, buf);
780 			break;
781 		}
782 		/*
783 		**  The `C' queue file command operates on the next line,
784 		**  so we use "gotctluser" to maintain state as follows:
785 		**      0 - no controlling user,
786 		**      1 - controlling user has been set but not used,
787 		**      2 - controlling user must be used on next iteration.
788 		*/
789 		if (gotctluser == 1)
790 			gotctluser++;
791 		else if (gotctluser == 2)
792 		{
793 			clrctluser();
794 			gotctluser = 0;
795 		}
796 	}
797 
798 	/* clear controlling user in case we break out prematurely */
799 	clrctluser();
800 
801 	FileName = NULL;
802 
803 	/*
804 	**  If we haven't read any lines, this queue file is empty.
805 	**  Arrange to remove it without referencing any null pointers.
806 	*/
807 
808 	if (LineNumber == 0)
809 	{
810 		errno = 0;
811 		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
812 	}
813 	return qfp;
814 }
815 /*
816 **  PRINTQUEUE -- print out a representation of the mail queue
817 **
818 **	Parameters:
819 **		none.
820 **
821 **	Returns:
822 **		none.
823 **
824 **	Side Effects:
825 **		Prints a listing of the mail queue on the standard output.
826 */
827 
828 printqueue()
829 {
830 	register WORK *w;
831 	FILE *f;
832 	int nrequests;
833 	char buf[MAXLINE];
834 	char cbuf[MAXLINE];
835 
836 	/*
837 	**  Read and order the queue.
838 	*/
839 
840 	nrequests = orderq(TRUE);
841 
842 	/*
843 	**  Print the work list that we have read.
844 	*/
845 
846 	/* first see if there is anything */
847 	if (nrequests <= 0)
848 	{
849 		printf("Mail queue is empty\n");
850 		return;
851 	}
852 
853 	la = getla();	/* get load average */
854 
855 	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
856 	if (nrequests > QUEUESIZE)
857 		printf(", only %d printed", QUEUESIZE);
858 	if (Verbose)
859 		printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
860 	else
861 		printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
862 	for (w = WorkQ; w != NULL; w = w->w_next)
863 	{
864 		struct stat st;
865 		auto time_t submittime = 0;
866 		long dfsize = -1;
867 		char message[MAXLINE];
868 		extern bool shouldqueue();
869 
870 		f = fopen(w->w_name, "r");
871 		if (f == NULL)
872 		{
873 			errno = 0;
874 			continue;
875 		}
876 		printf("%7s", w->w_name + 2);
877 		if (flock(fileno(f), LOCK_SH|LOCK_NB) < 0)
878 			printf("*");
879 		else if (shouldqueue(w->w_pri))
880 			printf("X");
881 		else
882 			printf(" ");
883 		errno = 0;
884 
885 		message[0] = '\0';
886 		cbuf[0] = '\0';
887 		while (fgets(buf, sizeof buf, f) != NULL)
888 		{
889 			fixcrlf(buf, TRUE);
890 			switch (buf[0])
891 			{
892 			  case 'M':	/* error message */
893 				(void) strcpy(message, &buf[1]);
894 				break;
895 
896 			  case 'S':	/* sender name */
897 				if (Verbose)
898 					printf("%8ld %10ld %.12s %.38s", dfsize,
899 					    w->w_pri, ctime(&submittime) + 4,
900 					    &buf[1]);
901 				else
902 					printf("%8ld %.16s %.45s", dfsize,
903 					    ctime(&submittime), &buf[1]);
904 				if (message[0] != '\0')
905 					printf("\n\t\t (%.60s)", message);
906 				break;
907 			  case 'C':	/* controlling user */
908 				if (strlen(buf) < MAXLINE-3)	/* sanity */
909 					(void) strcat(buf, ") ");
910 				cbuf[0] = cbuf[1] = '(';
911 				(void) strncpy(&cbuf[2], &buf[1], MAXLINE-1);
912 				cbuf[MAXLINE-1] = '\0';
913 				break;
914 
915 			  case 'R':	/* recipient name */
916 				if (cbuf[0] != '\0') {
917 					/* prepend controlling user to `buf' */
918 					(void) strncat(cbuf, &buf[1],
919 					              MAXLINE-strlen(cbuf));
920 					cbuf[MAXLINE-1] = '\0';
921 					(void) strcpy(buf, cbuf);
922 					cbuf[0] = '\0';
923 				}
924 				if (Verbose)
925 					printf("\n\t\t\t\t\t %.38s", &buf[1]);
926 				else
927 					printf("\n\t\t\t\t  %.45s", &buf[1]);
928 				break;
929 
930 			  case 'T':	/* creation time */
931 				submittime = atol(&buf[1]);
932 				break;
933 
934 			  case 'D':	/* data file name */
935 				if (stat(&buf[1], &st) >= 0)
936 					dfsize = st.st_size;
937 				break;
938 			}
939 		}
940 		if (submittime == (time_t) 0)
941 			printf(" (no control file)");
942 		printf("\n");
943 		(void) fclose(f);
944 	}
945 }
946 
947 # endif QUEUE
948 /*
949 **  QUEUENAME -- build a file name in the queue directory for this envelope.
950 **
951 **	Assigns an id code if one does not already exist.
952 **	This code is very careful to avoid trashing existing files
953 **	under any circumstances.
954 **
955 **	Parameters:
956 **		e -- envelope to build it in/from.
957 **		type -- the file type, used as the first character
958 **			of the file name.
959 **
960 **	Returns:
961 **		a pointer to the new file name (in a static buffer).
962 **
963 **	Side Effects:
964 **		Will create the qf file if no id code is
965 **		already assigned.  This will cause the envelope
966 **		to be modified.
967 */
968 
969 char *
970 queuename(e, type)
971 	register ENVELOPE *e;
972 	char type;
973 {
974 	static char buf[MAXNAME];
975 	static int pid = -1;
976 	char c1 = 'A';
977 	char c2 = 'A';
978 
979 	if (e->e_id == NULL)
980 	{
981 		char qf[20];
982 
983 		/* find a unique id */
984 		if (pid != getpid())
985 		{
986 			/* new process -- start back at "AA" */
987 			pid = getpid();
988 			c1 = 'A';
989 			c2 = 'A' - 1;
990 		}
991 		(void) sprintf(qf, "qfAA%05d", pid);
992 
993 		while (c1 < '~' || c2 < 'Z')
994 		{
995 			int i;
996 
997 			if (c2 >= 'Z')
998 			{
999 				c1++;
1000 				c2 = 'A' - 1;
1001 			}
1002 			qf[2] = c1;
1003 			qf[3] = ++c2;
1004 			if (tTd(7, 20))
1005 				printf("queuename: trying \"%s\"\n", qf);
1006 
1007 			i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
1008 			if (i < 0) {
1009 				if (errno != EEXIST) {
1010 					syserr("queuename: Cannot create \"%s\" in \"%s\"",
1011 						qf, QueueDir);
1012 					exit(EX_UNAVAILABLE);
1013 				}
1014 			} else {
1015 				(void) close(i);
1016 				break;
1017 			}
1018 		}
1019 		if (c1 >= '~' && c2 >= 'Z')
1020 		{
1021 			syserr("queuename: Cannot create \"%s\" in \"%s\"",
1022 				qf, QueueDir);
1023 			exit(EX_OSERR);
1024 		}
1025 		e->e_id = newstr(&qf[2]);
1026 		define('i', e->e_id, e);
1027 		if (tTd(7, 1))
1028 			printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1029 # ifdef LOG
1030 		if (LogLevel > 16)
1031 			syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
1032 # endif LOG
1033 	}
1034 
1035 	if (type == '\0')
1036 		return (NULL);
1037 	(void) sprintf(buf, "%cf%s", type, e->e_id);
1038 	if (tTd(7, 2))
1039 		printf("queuename: %s\n", buf);
1040 	return (buf);
1041 }
1042 /*
1043 **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1044 **
1045 **	Parameters:
1046 **		e -- the envelope to unlock.
1047 **
1048 **	Returns:
1049 **		none
1050 **
1051 **	Side Effects:
1052 **		unlocks the queue for `e'.
1053 */
1054 
1055 unlockqueue(e)
1056 	ENVELOPE *e;
1057 {
1058 	/* remove the transcript */
1059 # ifdef LOG
1060 	if (LogLevel > 19)
1061 		syslog(LOG_DEBUG, "%s: unlock", e->e_id);
1062 # endif LOG
1063 	if (!tTd(51, 4))
1064 		xunlink(queuename(e, 'x'));
1065 
1066 }
1067 /*
1068 **  GETCTLUSER -- return controlling user if mailing to prog or file
1069 **
1070 **	Check for a "|" or "/" at the beginning of the address.  If
1071 **	found, return a controlling username.
1072 **
1073 **	Parameters:
1074 **		a - the address to check out
1075 **
1076 **	Returns:
1077 **		Either NULL, if we werent mailing to a program or file,
1078 **		or a controlling user name (possibly in getpwuid's
1079 **		static buffer).
1080 **
1081 **	Side Effects:
1082 **		none.
1083 */
1084 
1085 char *
1086 getctluser(a)
1087 	ADDRESS *a;
1088 {
1089 	extern ADDRESS *getctladdr();
1090 	struct passwd *pw;
1091 	char *retstr;
1092 
1093 	/*
1094 	**  Get unquoted user for file, program or user.name check.
1095 	**  N.B. remove this code block to always emit controlling
1096 	**  addresses (at the expense of backward compatibility).
1097 	*/
1098 
1099 	{
1100 		char buf[MAXNAME];
1101 		(void) strncpy(buf, a->q_paddr, MAXNAME);
1102 		buf[MAXNAME-1] = '\0';
1103 		stripquotes(buf, TRUE);
1104 
1105 		if (buf[0] != '|' && buf[0] != '/')
1106 			return((char *)NULL);
1107 	}
1108 
1109 	a = getctladdr(a);		/* find controlling address */
1110 
1111 	if (a != NULL && a->q_uid != 0 && (pw = getpwuid(a->q_uid)) != NULL)
1112 		retstr = pw->pw_name;
1113 	else				/* use default user */
1114 		retstr = DefUser;
1115 
1116 	if (tTd(40, 5))
1117 		printf("Set controlling user for `%s' to `%s'\n",
1118 		       (a == NULL)? "<null>": a->q_paddr, retstr);
1119 
1120 	return(retstr);
1121 }
1122 /*
1123 **  SETCTLUSER - sets `CtlUser' to controlling user
1124 **  CLRCTLUSER - clears controlling user (no params, nothing returned)
1125 **
1126 **	These routines manipulate `CtlUser'.
1127 **
1128 **	Parameters:
1129 **		str  - controlling user as passed to setctluser()
1130 **
1131 **	Returns:
1132 **		None.
1133 **
1134 **	Side Effects:
1135 **		`CtlUser' is changed.
1136 */
1137 
1138 static char CtlUser[MAXNAME];
1139 
1140 setctluser(str)
1141 register char *str;
1142 {
1143 	(void) strncpy(CtlUser, str, MAXNAME);
1144 	CtlUser[MAXNAME-1] = '\0';
1145 }
1146 
1147 clrctluser()
1148 {
1149 	CtlUser[0] = '\0';
1150 }
1151 
1152 /*
1153 **  SETCTLADDR -- create a controlling address
1154 **
1155 **	If global variable `CtlUser' is set and we are given a valid
1156 **	address, make that address a controlling address; change the
1157 **	`q_uid', `q_gid', and `q_ruser' fields and set QGOODUID.
1158 **
1159 **	Parameters:
1160 **		a - address for which control uid/gid info may apply
1161 **
1162 **	Returns:
1163 **		None.
1164 **
1165 **	Side Effects:
1166 **		Fills in uid/gid fields in address and sets QGOODUID
1167 **		flag if appropriate.
1168 */
1169 
1170 setctladdr(a)
1171 	ADDRESS *a;
1172 {
1173 	struct passwd *pw;
1174 
1175 	/*
1176 	**  If there is no current controlling user, or we were passed a
1177 	**  NULL addr ptr or we already have a controlling user, return.
1178 	*/
1179 
1180 	if (CtlUser[0] == '\0' || a == NULL || a->q_ruser)
1181 		return;
1182 
1183 	/*
1184 	**  Set up addr fields for controlling user.  If `CtlUser' is no
1185 	**  longer valid, use the default user/group.
1186 	*/
1187 
1188 	if ((pw = getpwnam(CtlUser)) != NULL)
1189 	{
1190 		if (a->q_home)
1191 			free(a->q_home);
1192 		a->q_home = newstr(pw->pw_dir);
1193 		a->q_uid = pw->pw_uid;
1194 		a->q_gid = pw->pw_gid;
1195 		a->q_ruser = newstr(CtlUser);
1196 	}
1197 	else
1198 	{
1199 		a->q_uid = DefUid;
1200 		a->q_gid = DefGid;
1201 		a->q_ruser = newstr(DefUser);
1202 	}
1203 
1204 	a->q_flags |= QGOODUID;		/* flag as a "ctladdr"  */
1205 
1206 	if (tTd(40, 5))
1207 		printf("Restored controlling user for `%s' to `%s'\n",
1208 		       a->q_paddr, a->q_ruser);
1209 }
1210