xref: /freebsd/contrib/sendmail/src/queue.c (revision f9e730bbb343d0a6aff3a9d4a7ea18dc1cf3ddc5)
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.210 (Berkeley) 10/15/1998 (with queueing)";
18 #else
19 static char sccsid[] = "@(#)queue.c	8.210 (Berkeley) 10/15/1998 (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, "Queue runner");
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 		clrcontrol();
623 		proc_list_clear();
624 
625 		/* Add parent process as first child item */
626 		proc_list_add(getpid(), "Queue runner child process");
627 		releasesignal(SIGCHLD);
628 		(void) setsignal(SIGCHLD, SIG_DFL);
629 		(void) setsignal(SIGHUP, intsig);
630 	}
631 
632 	sm_setproctitle(TRUE, "running queue: %s", QueueDir);
633 
634 	if (LogLevel > 69)
635 		sm_syslog(LOG_DEBUG, NOQID,
636 			"runqueue %s, pid=%d, forkflag=%d",
637 			QueueDir, getpid(), forkflag);
638 
639 	/*
640 	**  Release any resources used by the daemon code.
641 	*/
642 
643 # if DAEMON
644 	clrdaemon();
645 # endif /* DAEMON */
646 
647 	/* force it to run expensive jobs */
648 	NoConnect = FALSE;
649 
650 	/* drop privileges */
651 	if (geteuid() == (uid_t) 0)
652 		(void) drop_privileges(FALSE);
653 
654 	/*
655 	**  Create ourselves an envelope
656 	*/
657 
658 	CurEnv = &QueueEnvelope;
659 	e = newenvelope(&QueueEnvelope, CurEnv);
660 	e->e_flags = BlankEnvelope.e_flags;
661 
662 	/* make sure we have disconnected from parent */
663 	if (forkflag)
664 	{
665 		disconnect(1, e);
666 		QuickAbort = FALSE;
667 	}
668 
669 	/*
670 	**  Make sure the alias database is open.
671 	*/
672 
673 	initmaps(FALSE, e);
674 
675 	/*
676 	**  If we are running part of the queue, always ignore stored
677 	**  host status.
678 	*/
679 
680 	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
681 	    QueueLimitRecipient != NULL)
682 	{
683 		IgnoreHostStatus = TRUE;
684 		MinQueueAge = 0;
685 	}
686 
687 	/*
688 	**  Start making passes through the queue.
689 	**	First, read and sort the entire queue.
690 	**	Then, process the work in that order.
691 	**		But if you take too long, start over.
692 	*/
693 
694 	/* order the existing work requests */
695 	njobs = orderq(FALSE);
696 
697 	/* process them once at a time */
698 	while (WorkQ != NULL)
699 	{
700 		WORK *w = WorkQ;
701 
702 		WorkQ = WorkQ->w_next;
703 		e->e_to = NULL;
704 
705 		/*
706 		**  Ignore jobs that are too expensive for the moment.
707 		**
708 		**	Get new load average every 30 seconds.
709 		*/
710 
711 		if (current_la_time < curtime() - 30)
712 		{
713 			CurrentLA = getla();
714 			current_la_time = curtime();
715 		}
716 		if (shouldqueue(WkRecipFact, current_la_time))
717 		{
718 			char *msg = "Aborting queue run: load average too high";
719 
720 			if (Verbose)
721 				message("%s", msg);
722 			if (LogLevel > 8)
723 				sm_syslog(LOG_INFO, NOQID,
724 					"runqueue: %s",
725 					msg);
726 			break;
727 		}
728 		sequenceno++;
729 		if (shouldqueue(w->w_pri, w->w_ctime))
730 		{
731 			if (Verbose)
732 				message("");
733 			if (QueueSortOrder == QS_BYPRIORITY)
734 			{
735 				if (Verbose)
736 					message("Skipping %s (sequence %d of %d) and flushing rest of queue",
737 						w->w_name + 2,
738 						sequenceno,
739 						njobs);
740 				if (LogLevel > 8)
741 					sm_syslog(LOG_INFO, NOQID,
742 						"runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)",
743 						w->w_name + 2,
744 						w->w_pri,
745 						CurrentLA,
746 						sequenceno,
747 						njobs);
748 				break;
749 			}
750 			else if (Verbose)
751 				message("Skipping %s (sequence %d of %d)",
752 					w->w_name + 2, sequenceno, njobs);
753 		}
754 		else
755 		{
756 			pid_t pid;
757 
758 			if (Verbose)
759 			{
760 				message("");
761 				message("Running %s (sequence %d of %d)",
762 					w->w_name + 2, sequenceno, njobs);
763 			}
764 			pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
765 			errno = 0;
766 			if (pid != 0)
767 				(void) waitfor(pid);
768 		}
769 		free(w->w_name);
770 		if (w->w_host)
771 			free(w->w_host);
772 		free((char *) w);
773 	}
774 
775 	/* exit without the usual cleanup */
776 	e->e_id = NULL;
777 	finis(TRUE, ExitStat);
778 	/*NOTREACHED*/
779 	return TRUE;
780 }
781 
782 
783 /*
784 **  RUNQUEUEEVENT -- stub for use in setevent
785 */
786 
787 void
788 runqueueevent()
789 {
790 	DoQueueRun = TRUE;
791 }
792 /*
793 **  ORDERQ -- order the work queue.
794 **
795 **	Parameters:
796 **		doall -- if set, include everything in the queue (even
797 **			the jobs that cannot be run because the load
798 **			average is too high).  Otherwise, exclude those
799 **			jobs.
800 **
801 **	Returns:
802 **		The number of request in the queue (not necessarily
803 **		the number of requests in WorkQ however).
804 **
805 **	Side Effects:
806 **		Sets WorkQ to the queue of available work, in order.
807 */
808 
809 # define NEED_P		001
810 # define NEED_T		002
811 # define NEED_R		004
812 # define NEED_S		010
813 
814 static WORK	*WorkList = NULL;
815 static int	WorkListSize = 0;
816 
817 int
818 orderq(doall)
819 	bool doall;
820 {
821 	register struct dirent *d;
822 	register WORK *w;
823 	register char *p;
824 	DIR *f;
825 	register int i;
826 	int wn = -1;
827 	int wc;
828 	QUEUE_CHAR *check;
829 
830 	if (tTd(41, 1))
831 	{
832 		printf("orderq:\n");
833 
834 		check = QueueLimitId;
835 		while (check != NULL)
836 		{
837 			printf("\tQueueLimitId = %s\n",
838 			       check->queue_match);
839 			check = check->queue_next;
840 		}
841 
842 		check = QueueLimitSender;
843 		while (check != NULL)
844 		{
845 			printf("\tQueueLimitSender = %s\n",
846 			       check->queue_match);
847 			check = check->queue_next;
848 		}
849 
850 		check = QueueLimitRecipient;
851 		while (check != NULL)
852 		{
853 			printf("\tQueueLimitRecipient = %s\n",
854 			       check->queue_match);
855 			check = check->queue_next;
856 		}
857 	}
858 
859 	/* clear out old WorkQ */
860 	for (w = WorkQ; w != NULL; )
861 	{
862 		register WORK *nw = w->w_next;
863 
864 		WorkQ = nw;
865 		free(w->w_name);
866 		if (w->w_host)
867 			free(w->w_host);
868 		free((char *) w);
869 		w = nw;
870 	}
871 
872 	/* open the queue directory */
873 	f = opendir(".");
874 	if (f == NULL)
875 	{
876 		syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
877 		return (0);
878 	}
879 
880 	/*
881 	**  Read the work directory.
882 	*/
883 
884 	while ((d = readdir(f)) != NULL)
885 	{
886 		FILE *cf;
887 		int qfver = 0;
888 		char lbuf[MAXNAME + 1];
889 		extern bool strcontainedin __P((char *, char *));
890 
891 		if (tTd(41, 50))
892 			printf("orderq: checking %s\n", d->d_name);
893 
894 		/* is this an interesting entry? */
895 		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
896 			continue;
897 
898 		if (strlen(d->d_name) > MAXQFNAME)
899 		{
900 			if (Verbose)
901 				printf("orderq: %s too long, %d max characters\n",
902 					d->d_name, MAXQFNAME);
903 			if (LogLevel > 0)
904 				sm_syslog(LOG_ALERT, NOQID,
905 					"orderq: %s too long, %d max characters",
906 					d->d_name, MAXQFNAME);
907 			continue;
908 		}
909 
910 		check = QueueLimitId;
911 		while (check != NULL)
912 		{
913 			if (strcontainedin(check->queue_match, d->d_name))
914 				break;
915 			else
916 				check = check->queue_next;
917 		}
918 		if (QueueLimitId != NULL && check == NULL)
919 			continue;
920 
921 #ifdef PICKY_QF_NAME_CHECK
922 		/*
923 		**  Check queue name for plausibility.  This handles
924 		**  both old and new type ids.
925 		*/
926 
927 		p = d->d_name + 2;
928 		if (isupper(p[0]) && isupper(p[2]))
929 			p += 3;
930 		else if (isupper(p[1]))
931 			p += 2;
932 		else
933 			p = d->d_name;
934 		for (i = 0; isdigit(*p); p++)
935 			i++;
936 		if (i < 5 || *p != '\0')
937 		{
938 			if (Verbose)
939 				printf("orderq: bogus qf name %s\n", d->d_name);
940 			if (LogLevel > 0)
941 				sm_syslog(LOG_ALERT, NOQID,
942 					"orderq: bogus qf name %s",
943 					d->d_name);
944 			if (strlen(d->d_name) > (SIZE_T) MAXNAME)
945 				d->d_name[MAXNAME] = '\0';
946 			strcpy(lbuf, d->d_name);
947 			lbuf[0] = 'Q';
948 			(void) rename(d->d_name, lbuf);
949 			continue;
950 		}
951 #endif
952 
953 		/* open control file (if not too many files) */
954 		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
955 		{
956 			if (wn == MaxQueueRun && LogLevel > 0)
957 				sm_syslog(LOG_ALERT, NOQID,
958 					"WorkList for %s maxed out at %d",
959 					QueueDir, MaxQueueRun);
960 			continue;
961 		}
962 		if (wn >= WorkListSize)
963 		{
964 			extern void grow_wlist __P((void));
965 
966 			grow_wlist();
967 			if (wn >= WorkListSize)
968 				continue;
969 		}
970 
971 		cf = fopen(d->d_name, "r");
972 		if (cf == NULL)
973 		{
974 			/* this may be some random person sending hir msgs */
975 			/* syserr("orderq: cannot open %s", cbuf); */
976 			if (tTd(41, 2))
977 				printf("orderq: cannot open %s: %s\n",
978 					d->d_name, errstring(errno));
979 			errno = 0;
980 			wn--;
981 			continue;
982 		}
983 		w = &WorkList[wn];
984 		w->w_name = newstr(d->d_name);
985 		w->w_host = NULL;
986 		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
987 		w->w_tooyoung = FALSE;
988 
989 		/* make sure jobs in creation don't clog queue */
990 		w->w_pri = 0x7fffffff;
991 		w->w_ctime = 0;
992 
993 		/* extract useful information */
994 		i = NEED_P | NEED_T;
995 		if (QueueLimitSender != NULL)
996 			i |= NEED_S;
997 		if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
998 			i |= NEED_R;
999 		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
1000 		{
1001 			int c;
1002 			time_t age;
1003 			extern bool strcontainedin __P((char *, char *));
1004 
1005 			p = strchr(lbuf, '\n');
1006 			if (p != NULL)
1007 				*p = '\0';
1008 			else
1009 			{
1010 				/* flush rest of overly long line */
1011 				while ((c = getc(cf)) != EOF && c != '\n')
1012 					continue;
1013 			}
1014 
1015 			switch (lbuf[0])
1016 			{
1017 			  case 'V':
1018 				qfver = atoi(&lbuf[1]);
1019 				break;
1020 
1021 			  case 'P':
1022 				w->w_pri = atol(&lbuf[1]);
1023 				i &= ~NEED_P;
1024 				break;
1025 
1026 			  case 'T':
1027 				w->w_ctime = atol(&lbuf[1]);
1028 				i &= ~NEED_T;
1029 				break;
1030 
1031 			  case 'R':
1032 				if (w->w_host == NULL &&
1033 				    (p = strrchr(&lbuf[1], '@')) != NULL)
1034 					w->w_host = newstr(&p[1]);
1035 				if (QueueLimitRecipient == NULL)
1036 				{
1037 					i &= ~NEED_R;
1038 					break;
1039 				}
1040 				if (qfver > 0)
1041 				{
1042 					p = strchr(&lbuf[1], ':');
1043 					if (p == NULL)
1044 						p = &lbuf[1];
1045 				}
1046 				else
1047 					p = &lbuf[1];
1048 				check = QueueLimitRecipient;
1049 				while (check != NULL)
1050 				{
1051 					if (strcontainedin(check->queue_match,
1052 							   p))
1053 						break;
1054 					else
1055 						check = check->queue_next;
1056 				}
1057 				if (check != NULL)
1058 					i &= ~NEED_R;
1059 				break;
1060 
1061 			  case 'S':
1062 				  check = QueueLimitSender;
1063 				  while (check != NULL)
1064 				  {
1065 					  if (strcontainedin(check->queue_match,
1066 							     &lbuf[1]))
1067 						  break;
1068 					  else
1069 						  check = check->queue_next;
1070 				  }
1071 				  if (check != NULL)
1072 					  i &= ~NEED_S;
1073 				break;
1074 
1075 			  case 'K':
1076 				age = curtime() - (time_t) atol(&lbuf[1]);
1077 				if (age >= 0 && MinQueueAge > 0 &&
1078 				    age < MinQueueAge)
1079 					w->w_tooyoung = TRUE;
1080 				break;
1081 
1082 			  case 'N':
1083 				if (atol(&lbuf[1]) == 0)
1084 					w->w_tooyoung = FALSE;
1085 				break;
1086 			}
1087 		}
1088 		(void) fclose(cf);
1089 
1090 		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
1091 		    bitset(NEED_R|NEED_S, i))
1092 		{
1093 			/* don't even bother sorting this job in */
1094 			if (tTd(41, 49))
1095 				printf("skipping %s (%x)\n", w->w_name, i);
1096 			free(w->w_name);
1097 			if (w->w_host)
1098 				free(w->w_host);
1099 			wn--;
1100 		}
1101 	}
1102 	(void) closedir(f);
1103 	wn++;
1104 
1105 	wc = min(wn, WorkListSize);
1106 	if (wc > MaxQueueRun && MaxQueueRun > 0)
1107 		wc = MaxQueueRun;
1108 
1109 	if (QueueSortOrder == QS_BYHOST)
1110 	{
1111 		extern int workcmpf1();
1112 		extern int workcmpf2();
1113 
1114 		/*
1115 		**  Sort the work directory for the first time,
1116 		**  based on host name, lock status, and priority.
1117 		*/
1118 
1119 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
1120 
1121 		/*
1122 		**  If one message to host is locked, "lock" all messages
1123 		**  to that host.
1124 		*/
1125 
1126 		i = 0;
1127 		while (i < wc)
1128 		{
1129 			if (!WorkList[i].w_lock)
1130 			{
1131 				i++;
1132 				continue;
1133 			}
1134 			w = &WorkList[i];
1135 			while (++i < wc)
1136 			{
1137 				extern int sm_strcasecmp __P((char *, char *));
1138 
1139 				if (WorkList[i].w_host == NULL &&
1140 				    w->w_host == NULL)
1141 					WorkList[i].w_lock = TRUE;
1142 				else if (WorkList[i].w_host != NULL &&
1143 					 w->w_host != NULL &&
1144 					 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
1145 					WorkList[i].w_lock = TRUE;
1146 				else
1147 					break;
1148 			}
1149 		}
1150 
1151 		/*
1152 		**  Sort the work directory for the second time,
1153 		**  based on lock status, host name, and priority.
1154 		*/
1155 
1156 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
1157 	}
1158 	else if (QueueSortOrder == QS_BYTIME)
1159 	{
1160 		extern int workcmpf3();
1161 
1162 		/*
1163 		**  Simple sort based on submission time only.
1164 		*/
1165 
1166 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
1167 	}
1168 	else
1169 	{
1170 		extern int workcmpf0();
1171 
1172 		/*
1173 		**  Simple sort based on queue priority only.
1174 		*/
1175 
1176 		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
1177 	}
1178 
1179 	/*
1180 	**  Convert the work list into canonical form.
1181 	**	Should be turning it into a list of envelopes here perhaps.
1182 	*/
1183 
1184 	WorkQ = NULL;
1185 	for (i = wc; --i >= 0; )
1186 	{
1187 		w = (WORK *) xalloc(sizeof *w);
1188 		w->w_name = WorkList[i].w_name;
1189 		w->w_host = WorkList[i].w_host;
1190 		w->w_lock = WorkList[i].w_lock;
1191 		w->w_tooyoung = WorkList[i].w_tooyoung;
1192 		w->w_pri = WorkList[i].w_pri;
1193 		w->w_ctime = WorkList[i].w_ctime;
1194 		w->w_next = WorkQ;
1195 		WorkQ = w;
1196 	}
1197 	if (WorkList != NULL)
1198 		free(WorkList);
1199 	WorkList = NULL;
1200 	WorkListSize = 0;
1201 
1202 	if (tTd(40, 1))
1203 	{
1204 		for (w = WorkQ; w != NULL; w = w->w_next)
1205 			printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
1206 	}
1207 
1208 	return (wn);
1209 }
1210 /*
1211 **  GROW_WLIST -- make the work list larger
1212 **
1213 **	Parameters:
1214 **		none.
1215 **
1216 **	Returns:
1217 **		none.
1218 **
1219 **	Side Effects:
1220 **		Adds another QUEUESEGSIZE entries to WorkList if possible.
1221 **		It can fail if there isn't enough memory, so WorkListSize
1222 **		should be checked again upon return.
1223 */
1224 
1225 void
1226 grow_wlist()
1227 {
1228 	if (tTd(41, 1))
1229 		printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
1230 	if (WorkList == NULL)
1231 	{
1232 		WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
1233 		WorkListSize = QUEUESEGSIZE;
1234 	}
1235 	else
1236 	{
1237 		int newsize = WorkListSize + QUEUESEGSIZE;
1238 		WORK *newlist = (WORK *) realloc((char *)WorkList,
1239 					  (unsigned)sizeof(WORK) * (newsize + 1));
1240 
1241 		if (newlist != NULL)
1242 		{
1243 			WorkListSize = newsize;
1244 			WorkList = newlist;
1245 			if (LogLevel > 1)
1246 			{
1247 				sm_syslog(LOG_NOTICE, NOQID,
1248 					"grew WorkList for %s to %d",
1249 					QueueDir, WorkListSize);
1250 			}
1251 		}
1252 		else if (LogLevel > 0)
1253 		{
1254 			sm_syslog(LOG_ALERT, NOQID,
1255 				"FAILED to grow WorkList for %s to %d",
1256 				QueueDir, newsize);
1257 		}
1258 	}
1259 	if (tTd(41, 1))
1260 		printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
1261 }
1262 /*
1263 **  WORKCMPF0 -- simple priority-only compare function.
1264 **
1265 **	Parameters:
1266 **		a -- the first argument.
1267 **		b -- the second argument.
1268 **
1269 **	Returns:
1270 **		-1 if a < b
1271 **		 0 if a == b
1272 **		+1 if a > b
1273 **
1274 **	Side Effects:
1275 **		none.
1276 */
1277 
1278 int
1279 workcmpf0(a, b)
1280 	register WORK *a;
1281 	register WORK *b;
1282 {
1283 	long pa = a->w_pri;
1284 	long pb = b->w_pri;
1285 
1286 	if (pa == pb)
1287 		return 0;
1288 	else if (pa > pb)
1289 		return 1;
1290 	else
1291 		return -1;
1292 }
1293 /*
1294 **  WORKCMPF1 -- first compare function for ordering work based on host name.
1295 **
1296 **	Sorts on host name, lock status, and priority in that order.
1297 **
1298 **	Parameters:
1299 **		a -- the first argument.
1300 **		b -- the second argument.
1301 **
1302 **	Returns:
1303 **		<0 if a < b
1304 **		 0 if a == b
1305 **		>0 if a > b
1306 **
1307 **	Side Effects:
1308 **		none.
1309 */
1310 
1311 int
1312 workcmpf1(a, b)
1313 	register WORK *a;
1314 	register WORK *b;
1315 {
1316 	int i;
1317 	extern int sm_strcasecmp __P((char *, char *));
1318 
1319 	/* host name */
1320 	if (a->w_host != NULL && b->w_host == NULL)
1321 		return 1;
1322 	else if (a->w_host == NULL && b->w_host != NULL)
1323 		return -1;
1324 	if (a->w_host != NULL && b->w_host != NULL &&
1325 	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1326 		return i;
1327 
1328 	/* lock status */
1329 	if (a->w_lock != b->w_lock)
1330 		return b->w_lock - a->w_lock;
1331 
1332 	/* job priority */
1333 	return a->w_pri - b->w_pri;
1334 }
1335 /*
1336 **  WORKCMPF2 -- second compare function for ordering work based on host name.
1337 **
1338 **	Sorts on lock status, host name, and priority in that order.
1339 **
1340 **	Parameters:
1341 **		a -- the first argument.
1342 **		b -- the second argument.
1343 **
1344 **	Returns:
1345 **		<0 if a < b
1346 **		 0 if a == b
1347 **		>0 if a > b
1348 **
1349 **	Side Effects:
1350 **		none.
1351 */
1352 
1353 int
1354 workcmpf2(a, b)
1355 	register WORK *a;
1356 	register WORK *b;
1357 {
1358 	int i;
1359 	extern int sm_strcasecmp __P((char *, char *));
1360 
1361 	/* lock status */
1362 	if (a->w_lock != b->w_lock)
1363 		return a->w_lock - b->w_lock;
1364 
1365 	/* host name */
1366 	if (a->w_host != NULL && b->w_host == NULL)
1367 		return 1;
1368 	else if (a->w_host == NULL && b->w_host != NULL)
1369 		return -1;
1370 	if (a->w_host != NULL && b->w_host != NULL &&
1371 	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1372 		return i;
1373 
1374 	/* job priority */
1375 	return a->w_pri - b->w_pri;
1376 }
1377 /*
1378 **  WORKCMPF3 -- simple submission-time-only compare function.
1379 **
1380 **	Parameters:
1381 **		a -- the first argument.
1382 **		b -- the second argument.
1383 **
1384 **	Returns:
1385 **		-1 if a < b
1386 **		 0 if a == b
1387 **		+1 if a > b
1388 **
1389 **	Side Effects:
1390 **		none.
1391 */
1392 
1393 int
1394 workcmpf3(a, b)
1395 	register WORK *a;
1396 	register WORK *b;
1397 {
1398 	if (a->w_ctime > b->w_ctime)
1399 		return 1;
1400 	else if (a->w_ctime < b->w_ctime)
1401 		return -1;
1402 	else
1403 		return 0;
1404 }
1405 /*
1406 **  DOWORK -- do a work request.
1407 **
1408 **	Parameters:
1409 **		id -- the ID of the job to run.
1410 **		forkflag -- if set, run this in background.
1411 **		requeueflag -- if set, reinstantiate the queue quickly.
1412 **			This is used when expanding aliases in the queue.
1413 **			If forkflag is also set, it doesn't wait for the
1414 **			child.
1415 **		e - the envelope in which to run it.
1416 **
1417 **	Returns:
1418 **		process id of process that is running the queue job.
1419 **
1420 **	Side Effects:
1421 **		The work request is satisfied if possible.
1422 */
1423 
1424 pid_t
1425 dowork(id, forkflag, requeueflag, e)
1426 	char *id;
1427 	bool forkflag;
1428 	bool requeueflag;
1429 	register ENVELOPE *e;
1430 {
1431 	register pid_t pid;
1432 	extern bool readqf __P((ENVELOPE *));
1433 
1434 	if (tTd(40, 1))
1435 		printf("dowork(%s)\n", id);
1436 
1437 	/*
1438 	**  Fork for work.
1439 	*/
1440 
1441 	if (forkflag)
1442 	{
1443 		pid = fork();
1444 		if (pid < 0)
1445 		{
1446 			syserr("dowork: cannot fork");
1447 			return 0;
1448 		}
1449 		else if (pid > 0)
1450 		{
1451 			/* parent -- clean out connection cache */
1452 			mci_flush(FALSE, NULL);
1453 		}
1454 		else
1455 		{
1456 			/* child -- error messages to the transcript */
1457 			QuickAbort = OnlyOneError = FALSE;
1458 
1459 			/*
1460 			**  Since the delivery may happen in a child and the
1461 			**  parent does not wait, the parent may close the
1462 			**  maps thereby removing any shared memory used by
1463 			**  the map.  Therefore, open a copy of the maps for
1464 			**  the delivery process.
1465 			*/
1466 
1467 			initmaps(FALSE, e);
1468 		}
1469 	}
1470 	else
1471 	{
1472 		pid = 0;
1473 	}
1474 
1475 	if (pid == 0)
1476 	{
1477 		/*
1478 		**  CHILD
1479 		**	Lock the control file to avoid duplicate deliveries.
1480 		**		Then run the file as though we had just read it.
1481 		**	We save an idea of the temporary name so we
1482 		**		can recover on interrupt.
1483 		*/
1484 
1485 		/* set basic modes, etc. */
1486 		(void) alarm(0);
1487 		clearenvelope(e, FALSE);
1488 		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1489 		e->e_sendmode = SM_DELIVER;
1490 		e->e_errormode = EM_MAIL;
1491 		e->e_id = id;
1492 		GrabTo = UseErrorsTo = FALSE;
1493 		ExitStat = EX_OK;
1494 		if (forkflag)
1495 		{
1496 			disconnect(1, e);
1497 			OpMode = MD_DELIVER;
1498 		}
1499 		sm_setproctitle(TRUE, "%s: from queue", id);
1500 		if (LogLevel > 76)
1501 			sm_syslog(LOG_DEBUG, e->e_id,
1502 				"dowork, pid=%d",
1503 				getpid());
1504 
1505 		/* don't use the headers from sendmail.cf... */
1506 		e->e_header = NULL;
1507 
1508 		/* read the queue control file -- return if locked */
1509 		if (!readqf(e))
1510 		{
1511 			if (tTd(40, 4) && e->e_id != NULL)
1512 				printf("readqf(%s) failed\n", e->e_id);
1513 			e->e_id = NULL;
1514 			if (forkflag)
1515 				finis(FALSE, EX_OK);
1516 			else
1517 				return 0;
1518 		}
1519 
1520 		e->e_flags |= EF_INQUEUE;
1521 		eatheader(e, requeueflag);
1522 
1523 		if (requeueflag)
1524 			queueup(e, FALSE);
1525 
1526 		/* do the delivery */
1527 		sendall(e, SM_DELIVER);
1528 
1529 		/* finish up and exit */
1530 		if (forkflag)
1531 			finis(TRUE, ExitStat);
1532 		else
1533 			dropenvelope(e, TRUE);
1534 	}
1535 	e->e_id = NULL;
1536 	return pid;
1537 }
1538 /*
1539 **  READQF -- read queue file and set up environment.
1540 **
1541 **	Parameters:
1542 **		e -- the envelope of the job to run.
1543 **
1544 **	Returns:
1545 **		TRUE if it successfully read the queue file.
1546 **		FALSE otherwise.
1547 **
1548 **	Side Effects:
1549 **		The queue file is returned locked.
1550 */
1551 
1552 bool
1553 readqf(e)
1554 	register ENVELOPE *e;
1555 {
1556 	register FILE *qfp;
1557 	ADDRESS *ctladdr;
1558 	struct stat st;
1559 	char *bp;
1560 	int qfver = 0;
1561 	long hdrsize = 0;
1562 	register char *p;
1563 	char *orcpt = NULL;
1564 	bool nomore = FALSE;
1565 	char qf[MAXQFNAME];
1566 	char buf[MAXLINE];
1567 	extern ADDRESS *setctluser __P((char *, int));
1568 
1569 	/*
1570 	**  Read and process the file.
1571 	*/
1572 
1573 	strcpy(qf, queuename(e, 'q'));
1574 	qfp = fopen(qf, "r+");
1575 	if (qfp == NULL)
1576 	{
1577 		if (tTd(40, 8))
1578 			printf("readqf(%s): fopen failure (%s)\n",
1579 				qf, errstring(errno));
1580 		if (errno != ENOENT)
1581 			syserr("readqf: no control file %s", qf);
1582 		return FALSE;
1583 	}
1584 
1585 	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1586 	{
1587 		/* being processed by another queuer */
1588 		if (Verbose || tTd(40, 8))
1589 			printf("%s: locked\n", e->e_id);
1590 		if (LogLevel > 19)
1591 			sm_syslog(LOG_DEBUG, e->e_id, "locked");
1592 		(void) fclose(qfp);
1593 		return FALSE;
1594 	}
1595 
1596 	/*
1597 	**  Check the queue file for plausibility to avoid attacks.
1598 	*/
1599 
1600 	if (fstat(fileno(qfp), &st) < 0)
1601 	{
1602 		/* must have been being processed by someone else */
1603 		if (tTd(40, 8))
1604 			printf("readqf(%s): fstat failure (%s)\n",
1605 				qf, errstring(errno));
1606 		fclose(qfp);
1607 		return FALSE;
1608 	}
1609 
1610 	if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
1611 	    bitset(S_IWOTH|S_IWGRP, st.st_mode))
1612 	{
1613 		if (LogLevel > 0)
1614 		{
1615 			sm_syslog(LOG_ALERT, e->e_id,
1616 				"bogus queue file, uid=%d, mode=%o",
1617 				st.st_uid, st.st_mode);
1618 		}
1619 		if (tTd(40, 8))
1620 			printf("readqf(%s): bogus file\n", qf);
1621 		loseqfile(e, "bogus file uid in mqueue");
1622 		fclose(qfp);
1623 		return FALSE;
1624 	}
1625 
1626 	if (st.st_size == 0)
1627 	{
1628 		/* must be a bogus file -- if also old, just remove it */
1629 		if (st.st_ctime + 10 * 60 < curtime())
1630 		{
1631 			qf[0] = 'd';
1632 			(void) unlink(qf);
1633 			qf[0] = 'q';
1634 			(void) unlink(qf);
1635 		}
1636 		fclose(qfp);
1637 		return FALSE;
1638 	}
1639 
1640 	if (st.st_nlink == 0)
1641 	{
1642 		/*
1643 		**  Race condition -- we got a file just as it was being
1644 		**  unlinked.  Just assume it is zero length.
1645 		*/
1646 
1647 		fclose(qfp);
1648 		return FALSE;
1649 	}
1650 
1651 	/* good file -- save this lock */
1652 	e->e_lockfp = qfp;
1653 
1654 	/* do basic system initialization */
1655 	initsys(e);
1656 	define('i', e->e_id, e);
1657 
1658 	LineNumber = 0;
1659 	e->e_flags |= EF_GLOBALERRS;
1660 	OpMode = MD_DELIVER;
1661 	ctladdr = NULL;
1662 	e->e_dfino = -1;
1663 	e->e_msgsize = -1;
1664 	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1665 	{
1666 		register char *p;
1667 		u_long qflags;
1668 		ADDRESS *q;
1669 		int mid;
1670 		auto char *ep;
1671 
1672 		if (tTd(40, 4))
1673 			printf("+++++ %s\n", bp);
1674 		if (nomore)
1675 		{
1676 			/* hack attack */
1677 			syserr("SECURITY ALERT: extra data in qf: %s", bp);
1678 			fclose(qfp);
1679 			loseqfile(e, "bogus queue line");
1680 			return FALSE;
1681 		}
1682 		switch (bp[0])
1683 		{
1684 		  case 'V':		/* queue file version number */
1685 			qfver = atoi(&bp[1]);
1686 			if (qfver <= QF_VERSION)
1687 				break;
1688 			syserr("Version number in qf (%d) greater than max (%d)",
1689 				qfver, QF_VERSION);
1690 			fclose(qfp);
1691 			loseqfile(e, "unsupported qf file version");
1692 			return FALSE;
1693 
1694 		  case 'C':		/* specify controlling user */
1695 			ctladdr = setctluser(&bp[1], qfver);
1696 			break;
1697 
1698 		  case 'Q':		/* original recipient */
1699 			orcpt = newstr(&bp[1]);
1700 			break;
1701 
1702 		  case 'R':		/* specify recipient */
1703 			p = bp;
1704 			qflags = 0;
1705 			if (qfver >= 1)
1706 			{
1707 				/* get flag bits */
1708 				while (*++p != '\0' && *p != ':')
1709 				{
1710 					switch (*p)
1711 					{
1712 					  case 'N':
1713 						qflags |= QHASNOTIFY;
1714 						break;
1715 
1716 					  case 'S':
1717 						qflags |= QPINGONSUCCESS;
1718 						break;
1719 
1720 					  case 'F':
1721 						qflags |= QPINGONFAILURE;
1722 						break;
1723 
1724 					  case 'D':
1725 						qflags |= QPINGONDELAY;
1726 						break;
1727 
1728 					  case 'P':
1729 						qflags |= QPRIMARY;
1730 						break;
1731 					}
1732 				}
1733 			}
1734 			else
1735 				qflags |= QPRIMARY;
1736 			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
1737 			if (q != NULL)
1738 			{
1739 				q->q_alias = ctladdr;
1740 				if (qfver >= 1)
1741 					q->q_flags &= ~Q_PINGFLAGS;
1742 				q->q_flags |= qflags;
1743 				q->q_orcpt = orcpt;
1744 				(void) recipient(q, &e->e_sendqueue, 0, e);
1745 			}
1746 			orcpt = NULL;
1747 			break;
1748 
1749 		  case 'E':		/* specify error recipient */
1750 			/* no longer used */
1751 			break;
1752 
1753 		  case 'H':		/* header */
1754 			(void) chompheader(&bp[1], FALSE, NULL, e);
1755 			hdrsize += strlen(&bp[1]);
1756 			break;
1757 
1758 		  case 'L':		/* Solaris Content-Length: */
1759 		  case 'M':		/* message */
1760 			/* ignore this; we want a new message next time */
1761 			break;
1762 
1763 		  case 'S':		/* sender */
1764 			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
1765 			break;
1766 
1767 		  case 'B':		/* body type */
1768 			e->e_bodytype = newstr(&bp[1]);
1769 			break;
1770 
1771 #if _FFR_SAVE_CHARSET
1772 		  case 'X':		/* character set */
1773 			e->e_charset = newstr(&bp[1]);
1774 			break;
1775 #endif
1776 
1777 		  case 'D':		/* data file name */
1778 			/* obsolete -- ignore */
1779 			break;
1780 
1781 		  case 'T':		/* init time */
1782 			e->e_ctime = atol(&bp[1]);
1783 			break;
1784 
1785 		  case 'I':		/* data file's inode number */
1786 			/* regenerated below */
1787 			break;
1788 
1789 		  case 'K':		/* time of last deliver attempt */
1790 			e->e_dtime = atol(&buf[1]);
1791 			break;
1792 
1793 		  case 'N':		/* number of delivery attempts */
1794 			e->e_ntries = atoi(&buf[1]);
1795 
1796 			/* if this has been tried recently, let it be */
1797 			if (e->e_ntries > 0 &&
1798 			    MinQueueAge > 0 && e->e_dtime <= curtime() &&
1799 			    curtime() < e->e_dtime + MinQueueAge)
1800 			{
1801 				char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
1802 
1803 				if (Verbose || tTd(40, 8))
1804 					printf("%s: too young (%s)\n",
1805 						e->e_id, howlong);
1806 				if (LogLevel > 19)
1807 					sm_syslog(LOG_DEBUG, e->e_id,
1808 						"too young (%s)",
1809 						howlong);
1810 				e->e_id = NULL;
1811 				unlockqueue(e);
1812 				return FALSE;
1813 			}
1814 			break;
1815 
1816 		  case 'P':		/* message priority */
1817 			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
1818 			break;
1819 
1820 		  case 'F':		/* flag bits */
1821 			if (strncmp(bp, "From ", 5) == 0)
1822 			{
1823 				/* we are being spoofed! */
1824 				syserr("SECURITY ALERT: bogus qf line %s", bp);
1825 				fclose(qfp);
1826 				loseqfile(e, "bogus queue line");
1827 				return FALSE;
1828 			}
1829 			for (p = &bp[1]; *p != '\0'; p++)
1830 			{
1831 				switch (*p)
1832 				{
1833 				  case 'w':	/* warning sent */
1834 					e->e_flags |= EF_WARNING;
1835 					break;
1836 
1837 				  case 'r':	/* response */
1838 					e->e_flags |= EF_RESPONSE;
1839 					break;
1840 
1841 				  case '8':	/* has 8 bit data */
1842 					e->e_flags |= EF_HAS8BIT;
1843 					break;
1844 
1845 				  case 'b':	/* delete Bcc: header */
1846 					e->e_flags |= EF_DELETE_BCC;
1847 					break;
1848 
1849 				  case 'd':	/* envelope has DSN RET= */
1850 					e->e_flags |= EF_RET_PARAM;
1851 					break;
1852 
1853 				  case 'n':	/* don't return body */
1854 					e->e_flags |= EF_NO_BODY_RETN;
1855 					break;
1856 				}
1857 			}
1858 			break;
1859 
1860 		  case 'Z':		/* original envelope id from ESMTP */
1861 			e->e_envid = newstr(&bp[1]);
1862 			break;
1863 
1864 		  case '$':		/* define macro */
1865 			mid = macid(&bp[1], &ep);
1866 			define(mid, newstr(ep), e);
1867 			break;
1868 
1869 		  case '.':		/* terminate file */
1870 			nomore = TRUE;
1871 			break;
1872 
1873 		  default:
1874 			syserr("readqf: %s: line %d: bad line \"%s\"",
1875 				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
1876 			fclose(qfp);
1877 			loseqfile(e, "unrecognized line");
1878 			return FALSE;
1879 		}
1880 
1881 		if (bp != buf)
1882 			free(bp);
1883 	}
1884 
1885 	/*
1886 	**  If we haven't read any lines, this queue file is empty.
1887 	**  Arrange to remove it without referencing any null pointers.
1888 	*/
1889 
1890 	if (LineNumber == 0)
1891 	{
1892 		errno = 0;
1893 		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1894 		return TRUE;
1895 	}
1896 
1897 	/*
1898 	**  Arrange to read the data file.
1899 	*/
1900 
1901 	p = queuename(e, 'd');
1902 	e->e_dfp = fopen(p, "r");
1903 	if (e->e_dfp == NULL)
1904 	{
1905 		syserr("readqf: cannot open %s", p);
1906 	}
1907 	else
1908 	{
1909 		e->e_flags |= EF_HAS_DF;
1910 		if (fstat(fileno(e->e_dfp), &st) >= 0)
1911 		{
1912 			e->e_msgsize = st.st_size + hdrsize;
1913 			e->e_dfdev = st.st_dev;
1914 			e->e_dfino = st.st_ino;
1915 		}
1916 	}
1917 
1918 	return TRUE;
1919 }
1920 /*
1921 **  PRINTQUEUE -- print out a representation of the mail queue
1922 **
1923 **	Parameters:
1924 **		none.
1925 **
1926 **	Returns:
1927 **		none.
1928 **
1929 **	Side Effects:
1930 **		Prints a listing of the mail queue on the standard output.
1931 */
1932 
1933 void
1934 printqueue()
1935 {
1936 	register WORK *w;
1937 	FILE *f;
1938 	int nrequests;
1939 	char buf[MAXLINE];
1940 
1941 	/*
1942 	**  Check for permission to print the queue
1943 	*/
1944 
1945 	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
1946 	{
1947 		struct stat st;
1948 # ifdef NGROUPS_MAX
1949 		int n;
1950 		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
1951 # endif
1952 
1953 		if (stat(QueueDir, &st) < 0)
1954 		{
1955 			syserr("Cannot stat %s", QueueDir);
1956 			return;
1957 		}
1958 # ifdef NGROUPS_MAX
1959 		n = NGROUPS_MAX;
1960 		while (--n >= 0)
1961 		{
1962 			if (InitialGidSet[n] == st.st_gid)
1963 				break;
1964 		}
1965 		if (n < 0 && RealGid != st.st_gid)
1966 # else
1967 		if (RealGid != st.st_gid)
1968 # endif
1969 		{
1970 			usrerr("510 You are not permitted to see the queue");
1971 			setstat(EX_NOPERM);
1972 			return;
1973 		}
1974 	}
1975 
1976 	/*
1977 	**  Read and order the queue.
1978 	*/
1979 
1980 	nrequests = orderq(TRUE);
1981 
1982 	/*
1983 	**  Print the work list that we have read.
1984 	*/
1985 
1986 	/* first see if there is anything */
1987 	if (nrequests <= 0)
1988 	{
1989 		printf("Mail queue is empty\n");
1990 		return;
1991 	}
1992 
1993 	CurrentLA = getla();	/* get load average */
1994 
1995 	printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
1996 	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
1997 		printf(", only %d printed", MaxQueueRun);
1998 	if (Verbose)
1999 		printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
2000 	else
2001 		printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
2002 	for (w = WorkQ; w != NULL; w = w->w_next)
2003 	{
2004 		struct stat st;
2005 		auto time_t submittime = 0;
2006 		long dfsize;
2007 		int flags = 0;
2008 		int qfver;
2009 		char statmsg[MAXLINE];
2010 		char bodytype[MAXNAME + 1];
2011 
2012 		printf("%8s", w->w_name + 2);
2013 		f = fopen(w->w_name, "r");
2014 		if (f == NULL)
2015 		{
2016 			printf(" (job completed)\n");
2017 			errno = 0;
2018 			continue;
2019 		}
2020 		w->w_name[0] = 'd';
2021 		if (stat(w->w_name, &st) >= 0)
2022 			dfsize = st.st_size;
2023 		else
2024 			dfsize = -1;
2025 		if (w->w_lock)
2026 			printf("*");
2027 		else if (w->w_tooyoung)
2028 			printf("-");
2029 		else if (shouldqueue(w->w_pri, w->w_ctime))
2030 			printf("X");
2031 		else
2032 			printf(" ");
2033 		errno = 0;
2034 
2035 		statmsg[0] = bodytype[0] = '\0';
2036 		qfver = 0;
2037 		while (fgets(buf, sizeof buf, f) != NULL)
2038 		{
2039 			register int i;
2040 			register char *p;
2041 
2042 			fixcrlf(buf, TRUE);
2043 			switch (buf[0])
2044 			{
2045 			  case 'V':	/* queue file version */
2046 				qfver = atoi(&buf[1]);
2047 				break;
2048 
2049 			  case 'M':	/* error message */
2050 				if ((i = strlen(&buf[1])) >= sizeof statmsg)
2051 					i = sizeof statmsg - 1;
2052 				bcopy(&buf[1], statmsg, i);
2053 				statmsg[i] = '\0';
2054 				break;
2055 
2056 			  case 'B':	/* body type */
2057 				if ((i = strlen(&buf[1])) >= sizeof bodytype)
2058 					i = sizeof bodytype - 1;
2059 				bcopy(&buf[1], bodytype, i);
2060 				bodytype[i] = '\0';
2061 				break;
2062 
2063 			  case 'S':	/* sender name */
2064 				if (Verbose)
2065 					printf("%8ld %10ld%c%.12s %.78s",
2066 					    dfsize,
2067 					    w->w_pri,
2068 					    bitset(EF_WARNING, flags) ? '+' : ' ',
2069 					    ctime(&submittime) + 4,
2070 					    &buf[1]);
2071 				else
2072 					printf("%8ld %.16s %.45s", dfsize,
2073 					    ctime(&submittime), &buf[1]);
2074 				if (statmsg[0] != '\0' || bodytype[0] != '\0')
2075 				{
2076 					printf("\n    %10.10s", bodytype);
2077 					if (statmsg[0] != '\0')
2078 						printf("   (%.*s)",
2079 							Verbose ? 100 : 60,
2080 							statmsg);
2081 				}
2082 				break;
2083 
2084 			  case 'C':	/* controlling user */
2085 				if (Verbose)
2086 					printf("\n\t\t\t\t      (---%.74s---)",
2087 						&buf[1]);
2088 				break;
2089 
2090 			  case 'R':	/* recipient name */
2091 				p = &buf[1];
2092 				if (qfver >= 1)
2093 				{
2094 					p = strchr(p, ':');
2095 					if (p == NULL)
2096 						break;
2097 					p++;
2098 				}
2099 				if (Verbose)
2100 					printf("\n\t\t\t\t\t  %.78s", p);
2101 				else
2102 					printf("\n\t\t\t\t   %.45s", p);
2103 				break;
2104 
2105 			  case 'T':	/* creation time */
2106 				submittime = atol(&buf[1]);
2107 				break;
2108 
2109 			  case 'F':	/* flag bits */
2110 				for (p = &buf[1]; *p != '\0'; p++)
2111 				{
2112 					switch (*p)
2113 					{
2114 					  case 'w':
2115 						flags |= EF_WARNING;
2116 						break;
2117 					}
2118 				}
2119 			}
2120 		}
2121 		if (submittime == (time_t) 0)
2122 			printf(" (no control file)");
2123 		printf("\n");
2124 		(void) fclose(f);
2125 	}
2126 }
2127 
2128 # endif /* QUEUE */
2129 /*
2130 **  QUEUENAME -- build a file name in the queue directory for this envelope.
2131 **
2132 **	Assigns an id code if one does not already exist.
2133 **	This code is very careful to avoid trashing existing files
2134 **	under any circumstances.
2135 **
2136 **	Parameters:
2137 **		e -- envelope to build it in/from.
2138 **		type -- the file type, used as the first character
2139 **			of the file name.
2140 **
2141 **	Returns:
2142 **		a pointer to the new file name (in a static buffer).
2143 **
2144 **	Side Effects:
2145 **		If no id code is already assigned, queuename will
2146 **		assign an id code, create a qf file, and leave a
2147 **		locked, open-for-write file pointer in the envelope.
2148 */
2149 
2150 #ifndef ENOLCK
2151 # define ENOLCK		-1
2152 #endif
2153 #ifndef ENOSPC
2154 # define ENOSPC		-1
2155 #endif
2156 
2157 char *
2158 queuename(e, type)
2159 	register ENVELOPE *e;
2160 	int type;
2161 {
2162 	static pid_t pid = -1;
2163 	static char c0;
2164 	static char c1;
2165 	static char c2;
2166 	time_t now;
2167 	struct tm *tm;
2168 	static char buf[MAXNAME + 1];
2169 
2170 	if (e->e_id == NULL)
2171 	{
2172 		char qf[MAXQFNAME];
2173 
2174 		/* find a unique id */
2175 		if (pid != getpid())
2176 		{
2177 			/* new process -- start back at "AA" */
2178 			pid = getpid();
2179 			now = curtime();
2180 			tm = localtime(&now);
2181 			c0 = 'A' + tm->tm_hour;
2182 			c1 = 'A';
2183 			c2 = 'A' - 1;
2184 		}
2185 		(void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid);
2186 
2187 		while (c1 < '~' || c2 < 'Z')
2188 		{
2189 			int i;
2190 			int attempts = 0;
2191 
2192 			if (c2 >= 'Z')
2193 			{
2194 				c1++;
2195 				c2 = 'A' - 1;
2196 			}
2197 			qf[3] = c1;
2198 			qf[4] = ++c2;
2199 			if (tTd(7, 20))
2200 				printf("queuename: trying \"%s\"\n", qf);
2201 
2202 			i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
2203 			if (i < 0)
2204 			{
2205 				if (errno == EEXIST)
2206 					continue;
2207 				syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2208 					qf, QueueDir, geteuid());
2209 				finis(FALSE, EX_UNAVAILABLE);
2210 			}
2211 			do
2212 			{
2213 				if (attempts > 0)
2214 					sleep(attempts);
2215 				e->e_lockfp = 0;
2216 				if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
2217 				{
2218 					e->e_lockfp = fdopen(i, "w");
2219 					break;
2220 				}
2221 			} while ((errno == ENOLCK || errno == ENOSPC) &&
2222 				 attempts++ < 4);
2223 
2224 			/* Successful lock */
2225 			if (e->e_lockfp != 0)
2226 				break;
2227 
2228 #if !HASFLOCK
2229 			if (errno != EAGAIN && errno != EACCES)
2230 #else
2231 			if (errno != EWOULDBLOCK)
2232 #endif
2233 			{
2234 				syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)",
2235 					qf, QueueDir, geteuid());
2236 				finis(FALSE, EX_OSERR);
2237 			}
2238 
2239 			/* a reader got the file; abandon it and try again */
2240 			(void) close(i);
2241 		}
2242 		if (c1 >= '~' && c2 >= 'Z')
2243 		{
2244 			syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
2245 				qf, QueueDir, geteuid());
2246 			finis(FALSE, EX_OSERR);
2247 		}
2248 		e->e_id = newstr(&qf[2]);
2249 		define('i', e->e_id, e);
2250 		if (tTd(7, 1))
2251 			printf("queuename: assigned id %s, env=%lx\n",
2252 			       e->e_id, (u_long) e);
2253 		if (tTd(7, 9))
2254 		{
2255 			printf("  lockfd=");
2256 			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
2257 		}
2258 		if (LogLevel > 93)
2259 			sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
2260 	}
2261 
2262 	if (type == '\0')
2263 		return (NULL);
2264 	(void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id);
2265 	if (tTd(7, 2))
2266 		printf("queuename: %s\n", buf);
2267 	return (buf);
2268 }
2269 /*
2270 **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
2271 **
2272 **	Parameters:
2273 **		e -- the envelope to unlock.
2274 **
2275 **	Returns:
2276 **		none
2277 **
2278 **	Side Effects:
2279 **		unlocks the queue for `e'.
2280 */
2281 
2282 void
2283 unlockqueue(e)
2284 	ENVELOPE *e;
2285 {
2286 	if (tTd(51, 4))
2287 		printf("unlockqueue(%s)\n",
2288 			e->e_id == NULL ? "NOQUEUE" : e->e_id);
2289 
2290 	/* if there is a lock file in the envelope, close it */
2291 	if (e->e_lockfp != NULL)
2292 		xfclose(e->e_lockfp, "unlockqueue", e->e_id);
2293 	e->e_lockfp = NULL;
2294 
2295 	/* don't create a queue id if we don't already have one */
2296 	if (e->e_id == NULL)
2297 		return;
2298 
2299 	/* remove the transcript */
2300 	if (LogLevel > 87)
2301 		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
2302 	if (!tTd(51, 104))
2303 		xunlink(queuename(e, 'x'));
2304 
2305 }
2306 /*
2307 **  SETCTLUSER -- create a controlling address
2308 **
2309 **	Create a fake "address" given only a local login name; this is
2310 **	used as a "controlling user" for future recipient addresses.
2311 **
2312 **	Parameters:
2313 **		user -- the user name of the controlling user.
2314 **		qfver -- the version stamp of this qf file.
2315 **
2316 **	Returns:
2317 **		An address descriptor for the controlling user.
2318 **
2319 **	Side Effects:
2320 **		none.
2321 */
2322 
2323 ADDRESS *
2324 setctluser(user, qfver)
2325 	char *user;
2326 	int qfver;
2327 {
2328 	register ADDRESS *a;
2329 	struct passwd *pw;
2330 	char *p;
2331 
2332 	/*
2333 	**  See if this clears our concept of controlling user.
2334 	*/
2335 
2336 	if (user == NULL || *user == '\0')
2337 		return NULL;
2338 
2339 	/*
2340 	**  Set up addr fields for controlling user.
2341 	*/
2342 
2343 	a = (ADDRESS *) xalloc(sizeof *a);
2344 	bzero((char *) a, sizeof *a);
2345 
2346 	if (*user == '\0')
2347 	{
2348 		p = NULL;
2349 		a->q_user = newstr(DefUser);
2350 	}
2351 	else if (*user == ':')
2352 	{
2353 		p = &user[1];
2354 		a->q_user = newstr(p);
2355 	}
2356 	else
2357 	{
2358 		p = strtok(user, ":");
2359 		a->q_user = newstr(user);
2360 		if (qfver >= 2)
2361 		{
2362 			if ((p = strtok(NULL, ":")) != NULL)
2363 				a->q_uid = atoi(p);
2364 			if ((p = strtok(NULL, ":")) != NULL)
2365 				a->q_gid = atoi(p);
2366 			if ((p = strtok(NULL, ":")) != NULL)
2367 				a->q_flags |= QGOODUID;
2368 		}
2369 		else if ((pw = sm_getpwnam(user)) != NULL)
2370 		{
2371 			if (strcmp(pw->pw_dir, "/") == 0)
2372 				a->q_home = "";
2373 			else
2374 				a->q_home = newstr(pw->pw_dir);
2375 			a->q_uid = pw->pw_uid;
2376 			a->q_gid = pw->pw_gid;
2377 			a->q_flags |= QGOODUID;
2378 		}
2379 	}
2380 
2381 	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr"  */
2382 	a->q_mailer = LocalMailer;
2383 	if (p == NULL)
2384 		a->q_paddr = a->q_user;
2385 	else
2386 		a->q_paddr = newstr(p);
2387 	return a;
2388 }
2389 /*
2390 **  LOSEQFILE -- save the qf as Qf and try to let someone know
2391 **
2392 **	Parameters:
2393 **		e -- the envelope (e->e_id will be used).
2394 **		why -- reported to whomever can hear.
2395 **
2396 **	Returns:
2397 **		none.
2398 */
2399 
2400 void
2401 loseqfile(e, why)
2402 	register ENVELOPE *e;
2403 	char *why;
2404 {
2405 	char *p;
2406 	char buf[MAXQFNAME + 1];
2407 
2408 	if (e == NULL || e->e_id == NULL)
2409 		return;
2410 	p = queuename(e, 'q');
2411 	if (strlen(p) > MAXQFNAME)
2412 	{
2413 		syserr("loseqfile: queuename (%s) too long", p);
2414 		return;
2415 	}
2416 	strcpy(buf, p);
2417 	p = queuename(e, 'Q');
2418 	if (rename(buf, p) < 0)
2419 		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2420 	else if (LogLevel > 0)
2421 		sm_syslog(LOG_ALERT, e->e_id,
2422 			"Losing %s: %s", buf, why);
2423 }
2424