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