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