check for CNAME loops
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
bee79b64
KB
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64 7 */
b2a81223 8
81b7d258 9# include "sendmail.h"
bee79b64
KB
10
11#ifndef lint
12#ifdef QUEUE
8d00c219 13static char sccsid[] = "@(#)queue.c 6.61 (Berkeley) %G% (with queueing)";
bee79b64 14#else
8d00c219 15static char sccsid[] = "@(#)queue.c 6.61 (Berkeley) %G% (without queueing)";
bee79b64
KB
16#endif
17#endif /* not lint */
18
aba51985 19# include <signal.h>
81b7d258 20# include <errno.h>
3fbc69d6 21# include <pwd.h>
6feb509e 22# include <dirent.h>
4287d84d 23
76b607b2
EA
24# ifdef QUEUE
25
81b7d258 26/*
7338e3d4
EA
27** Work queue.
28*/
29
30struct work
31{
32 char *w_name; /* name of control file */
33 long w_pri; /* priority of message, see below */
f746582a 34 time_t w_ctime; /* creation time of message */
7338e3d4
EA
35 struct work *w_next; /* next in queue */
36};
37
38typedef struct work WORK;
39
40WORK *WorkQ; /* queue of things to be done */
41\f/*
81b7d258
EA
42** QUEUEUP -- queue a message up for future transmission.
43**
81b7d258 44** Parameters:
dd1fe05b 45** e -- the envelope to queue up.
d0bd03ce
EA
46** queueall -- if TRUE, queue all addresses, rather than
47** just those with the QQUEUEUP flag set.
7338e3d4 48** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
49**
50** Returns:
3620ad97 51** none.
81b7d258
EA
52**
53** Side Effects:
7338e3d4 54** The current request are saved in a control file.
3620ad97 55** The queue file is left locked.
81b7d258
EA
56*/
57
7338e3d4 58queueup(e, queueall, announce)
dd1fe05b 59 register ENVELOPE *e;
d0bd03ce 60 bool queueall;
7338e3d4 61 bool announce;
81b7d258 62{
2cce0c26 63 char *qf;
2cce0c26 64 register FILE *tfp;
81b7d258 65 register HDR *h;
d4f42161 66 register ADDRESS *q;
3620ad97
EA
67 int fd;
68 int i;
69 bool newid;
22293c34 70 register char *p;
4db45bf1 71 MAILER nullmailer;
3620ad97 72 char buf[MAXLINE], tf[MAXLINE];
81b7d258 73
9ccf54c4 74 /*
11e3f8b5 75 ** Create control file.
9ccf54c4 76 */
81b7d258 77
3620ad97
EA
78 newid = (e->e_id == NULL);
79 strcpy(tf, queuename(e, 't'));
80 tfp = e->e_lockfp;
81 if (tfp == NULL)
82 newid = FALSE;
83 if (newid)
4287d84d 84 {
3620ad97
EA
85 tfp = e->e_lockfp;
86 }
87 else
88 {
89 /* get a locked tf file */
90 for (i = 100; --i >= 0; )
4287d84d 91 {
3620ad97
EA
92 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
93 if (fd < 0)
4287d84d 94 {
3620ad97
EA
95 if (errno == EEXIST)
96 continue;
dc2cbc87 97notemp:
e0539260 98 syserr("!queueup: cannot create temp file %s", tf);
6680179d 99 }
f8a31c8e
EA
100
101 if (lockfile(fd, tf, LOCK_EX|LOCK_NB))
3620ad97 102 break;
f8a31c8e 103
3620ad97 104 close(fd);
dc2cbc87 105 sleep(i);
6680179d 106 }
dc2cbc87
EA
107 if (fd < 0)
108 goto notemp;
6680179d 109
3620ad97
EA
110 tfp = fdopen(fd, "w");
111 }
81b7d258 112
9678c96d 113 if (tTd(40, 1))
560a80d9 114 printf("queueing %s\n", e->e_id);
81b7d258 115
dd1fe05b
EA
116 /*
117 ** If there is no data file yet, create one.
118 */
119
120 if (e->e_df == NULL)
121 {
122 register FILE *dfp;
80482eb5 123 extern putbody();
dd1fe05b 124
2cce0c26 125 e->e_df = newstr(queuename(e, 'd'));
3f9ac8ea
RA
126 fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
127 if (fd < 0)
e0539260 128 syserr("!queueup: cannot create %s", e->e_df);
3f9ac8ea 129 dfp = fdopen(fd, "w");
2f6a8a78 130 (*e->e_putbody)(dfp, FileMailer, e, NULL);
bc854e30 131 (void) xfclose(dfp, "queueup dfp", e->e_id);
80482eb5 132 e->e_putbody = putbody;
dd1fe05b
EA
133 }
134
81b7d258
EA
135 /*
136 ** Output future work requests.
4e969be0
EA
137 ** Priority and creation time should be first, since
138 ** they are required by orderq.
81b7d258
EA
139 */
140
7338e3d4
EA
141 /* output message priority */
142 fprintf(tfp, "P%ld\n", e->e_msgpriority);
143
64912e7e
EA
144 /* output creation time */
145 fprintf(tfp, "T%ld\n", e->e_ctime);
146
96bfbc2c
EA
147 /* output type and name of data file */
148 if (e->e_bodytype != NULL)
149 fprintf(tfp, "B%s\n", e->e_bodytype);
2cce0c26 150 fprintf(tfp, "D%s\n", e->e_df);
81b7d258 151
baa0c390
EA
152 /* message from envelope, if it exists */
153 if (e->e_message != NULL)
154 fprintf(tfp, "M%s\n", e->e_message);
155
c2bdb1dd
EA
156 /* send various flag bits through */
157 p = buf;
158 if (bitset(EF_WARNING, e->e_flags))
159 *p++ = 'w';
160 if (bitset(EF_RESPONSE, e->e_flags))
161 *p++ = 'r';
162 *p++ = '\0';
163 if (buf[0] != '\0')
164 fprintf(tfp, "F%s\n", buf);
165
a9bac7a9 166 /* $r and $s and $_ macro values */
22293c34
EA
167 if ((p = macvalue('r', e)) != NULL)
168 fprintf(tfp, "$r%s\n", p);
169 if ((p = macvalue('s', e)) != NULL)
170 fprintf(tfp, "$s%s\n", p);
a9bac7a9
EA
171 if ((p = macvalue('_', e)) != NULL)
172 fprintf(tfp, "$_%s\n", p);
22293c34 173
81b7d258 174 /* output name of sender */
2cce0c26 175 fprintf(tfp, "S%s\n", e->e_from.q_paddr);
81b7d258 176
ca4d0c0b 177 /* output list of error recipients */
31739b4e 178 printctladdr(NULL, NULL);
ca4d0c0b
EA
179 for (q = e->e_errorqueue; q != NULL; q = q->q_next)
180 {
bc854e30 181 if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
ca4d0c0b 182 {
9cdb0b30 183 printctladdr(q, tfp);
ca4d0c0b
EA
184 fprintf(tfp, "E%s\n", q->q_paddr);
185 }
186 }
187
188 /* output list of recipient addresses */
dd1fe05b 189 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 190 {
374579b6 191 if (bitset(QQUEUEUP, q->q_flags) ||
bc854e30 192 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
4d237f16 193 {
9cdb0b30 194 printctladdr(q, tfp);
2cce0c26 195 fprintf(tfp, "R%s\n", q->q_paddr);
7338e3d4
EA
196 if (announce)
197 {
198 e->e_to = q->q_paddr;
b6edea3d 199 message("queued");
68f7099c 200 if (LogLevel > 8)
c0ae0b24 201 logdelivery(NULL, NULL, "queued", e);
7338e3d4
EA
202 e->e_to = NULL;
203 }
b9accadd
EA
204 if (tTd(40, 1))
205 {
206 printf("queueing ");
207 printaddr(q, FALSE);
208 }
4d237f16 209 }
81b7d258
EA
210 }
211
7338e3d4
EA
212 /*
213 ** Output headers for this message.
214 ** Expand macros completely here. Queue run will deal with
215 ** everything as absolute headers.
216 ** All headers that must be relative to the recipient
217 ** can be cracked later.
4db45bf1
EA
218 ** We set up a "null mailer" -- i.e., a mailer that will have
219 ** no effect on the addresses as they are output.
7338e3d4
EA
220 */
221
1dbda134 222 bzero((char *) &nullmailer, sizeof nullmailer);
68f7099c
EA
223 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
224 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
281ef7f0 225 nullmailer.m_eol = "\n";
4db45bf1 226
2bee003d 227 define('g', "\201f", e);
dd1fe05b 228 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 229 {
1dbda134
EA
230 extern bool bitzerop();
231
83e9910e 232 /* don't output null headers */
81b7d258
EA
233 if (h->h_value == NULL || h->h_value[0] == '\0')
234 continue;
83e9910e
EA
235
236 /* don't output resent headers on non-resent messages */
237 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
238 continue;
239
240 /* output this header */
2cce0c26 241 fprintf(tfp, "H");
83e9910e
EA
242
243 /* if conditional, output the set of conditions */
1dbda134
EA
244 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
245 {
246 int j;
247
0e306e7f 248 (void) putc('?', tfp);
1dbda134
EA
249 for (j = '\0'; j <= '\177'; j++)
250 if (bitnset(j, h->h_mflags))
0e306e7f
EA
251 (void) putc(j, tfp);
252 (void) putc('?', tfp);
1dbda134 253 }
83e9910e
EA
254
255 /* output the header: expand macros, convert addresses */
9416f3a0
EA
256 if (bitset(H_DEFAULT, h->h_flags))
257 {
258 (void) expand(h->h_value, buf, &buf[sizeof buf], e);
3ba0846a 259 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 260 }
4d237f16 261 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d 262 {
c2bdb1dd
EA
263 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
264
265 if (bitset(H_FROM, h->h_flags))
266 oldstyle = FALSE;
267
268 commaize(h, h->h_value, tfp, oldstyle,
a4076aed 269 &nullmailer, e);
611b763d 270 }
4d237f16
EA
271 else
272 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
273 }
274
275 /*
276 ** Clean up.
277 */
278
e6d43796 279 fflush(tfp);
b6212c1e 280 fsync(fileno(tfp));
e6d43796
EA
281 if (ferror(tfp))
282 {
283 if (newid)
284 syserr("!552 Error writing control file %s", tf);
285 else
286 syserr("!452 Error writing control file %s", tf);
287 }
288
3620ad97
EA
289 if (!newid)
290 {
291 qf = queuename(e, 'q');
292 if (rename(tf, qf) < 0)
293 syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df);
294 if (e->e_lockfp != NULL)
bc854e30 295 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
3620ad97
EA
296 e->e_lockfp = tfp;
297 }
298 else
299 qf = tf;
6680179d 300 errno = 0;
1a13ccd8 301
9678c96d
EA
302# ifdef LOG
303 /* save log info */
68f7099c 304 if (LogLevel > 79)
a8f5bbff 305 syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
f3d8f6d6 306# endif /* LOG */
3620ad97 307 return;
81b7d258 308}
d2213d6c
EA
309
310printctladdr(a, tfp)
9cdb0b30 311 register ADDRESS *a;
d2213d6c
EA
312 FILE *tfp;
313{
9cdb0b30
EA
314 char *uname;
315 register struct passwd *pw;
316 register ADDRESS *q;
317 uid_t uid;
318 static ADDRESS *lastctladdr;
319 static uid_t lastuid;
d2213d6c 320
9cdb0b30 321 /* initialization */
31739b4e 322 if (a == NULL || tfp == NULL)
d2213d6c 323 {
31739b4e 324 if (lastctladdr != NULL && tfp != NULL)
9cdb0b30
EA
325 fprintf(tfp, "C\n");
326 lastctladdr = NULL;
327 lastuid = 0;
d2213d6c
EA
328 return;
329 }
9cdb0b30
EA
330
331 /* find the active uid */
332 q = getctladdr(a);
333 if (q == NULL)
334 uid = 0;
335 else
336 uid = q->q_uid;
337
338 /* if a is an alias, use that for printing */
339 if (a->q_alias != NULL)
340 a = a->q_alias;
341
342 /* check to see if this is the same as last time */
343 if (lastctladdr != NULL && uid == lastuid &&
344 strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
345 return;
346 lastuid = uid;
347 lastctladdr = a;
348
349 if (uid == 0 || (pw = getpwuid(uid)) == NULL)
f7894324 350 uname = "";
d2213d6c 351 else
9cdb0b30
EA
352 uname = pw->pw_name;
353
354 fprintf(tfp, "C%s:%s\n", uname, a->q_paddr);
d2213d6c
EA
355}
356
81b7d258
EA
357\f/*
358** RUNQUEUE -- run the jobs in the queue.
359**
360** Gets the stuff out of the queue in some presumably logical
361** order and processes them.
362**
363** Parameters:
2e3062fe
EA
364** forkflag -- TRUE if the queue scanning should be done in
365** a child process. We double-fork so it is not our
366** child and we don't have to clean up after it.
81b7d258
EA
367**
368** Returns:
369** none.
370**
371** Side Effects:
372** runs things in the mail queue.
373*/
374
ca4d0c0b
EA
375ENVELOPE QueueEnvelope; /* the queue run envelope */
376
377runqueue(forkflag)
2cf55cb7 378 bool forkflag;
81b7d258 379{
ca4d0c0b
EA
380 register ENVELOPE *e;
381 extern ENVELOPE BlankEnvelope;
4bc44f60
EA
382
383 /*
384 ** If no work will ever be selected, don't even bother reading
385 ** the queue.
386 */
387
3620ad97 388 CurrentLA = getla(); /* get load average */
3f9ac8ea 389
986065ef 390 if (shouldqueue(0L, curtime()))
4bc44f60
EA
391 {
392 if (Verbose)
393 printf("Skipping queue run -- load average too high\n");
fe80f8e1
EA
394 if (forkflag && QueueIntvl != 0)
395 (void) setevent(QueueIntvl, runqueue, TRUE);
ca4d0c0b 396 return;
4bc44f60
EA
397 }
398
b6dffdf5
EA
399 /*
400 ** See if we want to go off and do other useful work.
401 */
2cf55cb7
EA
402
403 if (forkflag)
404 {
6d06102a
EA
405 int pid;
406
407 pid = dofork();
408 if (pid != 0)
2cf55cb7 409 {
0df908a9 410 extern void reapchild();
c8ad461a 411
6d06102a 412 /* parent -- pick up intermediate zombie */
c8ad461a 413#ifndef SIGCHLD
7338e3d4 414 (void) waitfor(pid);
f3d8f6d6 415#else /* SIGCHLD */
c8ad461a 416 (void) signal(SIGCHLD, reapchild);
f3d8f6d6 417#endif /* SIGCHLD */
c4442979 418 if (QueueIntvl != 0)
611b763d 419 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
420 return;
421 }
6d06102a 422 /* child -- double fork */
c8ad461a 423#ifndef SIGCHLD
6d06102a
EA
424 if (fork() != 0)
425 exit(EX_OK);
f3d8f6d6 426#else /* SIGCHLD */
c8ad461a 427 (void) signal(SIGCHLD, SIG_DFL);
f3d8f6d6 428#endif /* SIGCHLD */
b6dffdf5 429 }
2e3062fe 430
3f9ac8ea 431 setproctitle("running queue: %s", QueueDir);
2e3062fe 432
36a4e219 433# ifdef LOG
68f7099c 434 if (LogLevel > 69)
ca4d0c0b
EA
435 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
436 QueueDir, getpid(), forkflag);
f3d8f6d6 437# endif /* LOG */
81b7d258 438
eb8af3ce
EA
439 /*
440 ** Release any resources used by the daemon code.
441 */
442
443# ifdef DAEMON
444 clrdaemon();
f3d8f6d6 445# endif /* DAEMON */
eb8af3ce 446
ca4d0c0b
EA
447 /*
448 ** Create ourselves an envelope
449 */
450
451 CurEnv = &QueueEnvelope;
fda58daa 452 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
453 e->e_flags = BlankEnvelope.e_flags;
454
a78155b0
EA
455 /*
456 ** Make sure the alias database is open.
457 */
458
36b09297 459 initmaps(FALSE, e);
a78155b0 460
b6dffdf5
EA
461 /*
462 ** Start making passes through the queue.
463 ** First, read and sort the entire queue.
464 ** Then, process the work in that order.
465 ** But if you take too long, start over.
b6dffdf5 466 */
81b7d258 467
6d06102a 468 /* order the existing work requests */
8ff78b51 469 (void) orderq(FALSE);
291fa573 470
6d06102a
EA
471 /* process them once at a time */
472 while (WorkQ != NULL)
2cf55cb7 473 {
6d06102a 474 WORK *w = WorkQ;
2cf55cb7 475
6d06102a 476 WorkQ = WorkQ->w_next;
a7dc53bd
EA
477
478 /*
479 ** Ignore jobs that are too expensive for the moment.
480 */
481
482 if (shouldqueue(w->w_pri, w->w_ctime))
483 {
484 if (Verbose)
485 printf("\nSkipping %s\n", w->w_name + 2);
a7dc53bd 486 }
1c791deb
EA
487 else
488 {
489 dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
490 }
6d06102a
EA
491 free(w->w_name);
492 free((char *) w);
2cf55cb7 493 }
37ea3cbf
EA
494
495 /* exit without the usual cleanup */
4e20c4d2
EA
496 e->e_id = NULL;
497 finis();
aba51985
EA
498}
499\f/*
81b7d258
EA
500** ORDERQ -- order the work queue.
501**
502** Parameters:
2e3062fe
EA
503** doall -- if set, include everything in the queue (even
504** the jobs that cannot be run because the load
505** average is too high). Otherwise, exclude those
506** jobs.
81b7d258
EA
507**
508** Returns:
e65b95c4
EA
509** The number of request in the queue (not necessarily
510** the number of requests in WorkQ however).
81b7d258
EA
511**
512** Side Effects:
513** Sets WorkQ to the queue of available work, in order.
514*/
515
4e969be0
EA
516# define NEED_P 001
517# define NEED_T 002
d6c28d1a
EA
518# define NEED_R 004
519# define NEED_S 010
81b7d258 520
38d3b461
EA
521# ifndef DIR
522# define DIR FILE
523# define direct dir
524# define opendir(d) fopen(d, "r")
07a8f29b 525# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
526static struct dir dbuf;
527# define closedir(f) fclose(f)
528# endif DIR
529
2e3062fe
EA
530orderq(doall)
531 bool doall;
81b7d258 532{
9114f86c 533 register struct dirent *d;
81b7d258 534 register WORK *w;
ccd1d833 535 DIR *f;
81b7d258 536 register int i;
4e969be0 537 WORK wlist[QUEUESIZE+1];
0490b7d7 538 int wn = -1;
81b7d258 539 extern workcmpf();
81b7d258 540
d6c28d1a
EA
541 if (tTd(41, 1))
542 {
543 printf("orderq:\n");
544 if (QueueLimitId != NULL)
545 printf("\tQueueLimitId = %s\n", QueueLimitId);
546 if (QueueLimitSender != NULL)
547 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
548 if (QueueLimitRecipient != NULL)
549 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
550 }
551
81b7d258
EA
552 /* clear out old WorkQ */
553 for (w = WorkQ; w != NULL; )
554 {
555 register WORK *nw = w->w_next;
556
557 WorkQ = nw;
558 free(w->w_name);
559 free((char *) w);
560 w = nw;
561 }
562
563 /* open the queue directory */
6bbaf971 564 f = opendir(".");
81b7d258
EA
565 if (f == NULL)
566 {
6bbaf971 567 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 568 return (0);
81b7d258
EA
569 }
570
571 /*
572 ** Read the work directory.
573 */
574
0490b7d7 575 while ((d = readdir(f)) != NULL)
81b7d258 576 {
81b7d258 577 FILE *cf;
7338e3d4 578 char lbuf[MAXNAME];
d6c28d1a 579 extern bool strcontainedin();
81b7d258
EA
580
581 /* is this an interesting entry? */
07a8f29b
EA
582 if (d->d_ino == 0)
583 continue;
584# ifdef DEBUG
585 if (tTd(40, 10))
586 printf("orderq: %12s\n", d->d_name);
587# endif DEBUG
2cce0c26 588 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
589 continue;
590
d6c28d1a
EA
591 if (QueueLimitId != NULL &&
592 !strcontainedin(QueueLimitId, d->d_name))
593 continue;
594
45ce4b34
EA
595 /*
596 ** Check queue name for plausibility. This handles
597 ** both old and new type ids.
598 */
599
600 i = strlen(d->d_name);
601 if (i != 9 && i != 10)
68f7099c
EA
602 {
603 if (Verbose)
604 printf("orderq: bogus qf name %s\n", d->d_name);
605#ifdef LOG
606 if (LogLevel > 3)
73f6752a 607 syslog(LOG_CRIT, "orderq: bogus qf name %s",
68f7099c
EA
608 d->d_name);
609#endif
610 if (strlen(d->d_name) >= MAXNAME)
611 d->d_name[MAXNAME - 1] = '\0';
612 strcpy(lbuf, d->d_name);
613 lbuf[0] = 'Q';
614 (void) rename(d->d_name, lbuf);
615 continue;
616 }
617
0490b7d7 618 /* yes -- open control file (if not too many files) */
4e969be0 619 if (++wn >= QUEUESIZE)
0490b7d7 620 continue;
d6c28d1a 621
6bbaf971 622 cf = fopen(d->d_name, "r");
81b7d258
EA
623 if (cf == NULL)
624 {
91f69adf
EA
625 /* this may be some random person sending hir msgs */
626 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
627 if (tTd(41, 2))
628 printf("orderq: cannot open %s (%d)\n",
629 d->d_name, errno);
91f69adf 630 errno = 0;
bd0712bd 631 wn--;
81b7d258
EA
632 continue;
633 }
4e969be0
EA
634 w = &wlist[wn];
635 w->w_name = newstr(d->d_name);
81b7d258 636
4ff794a3 637 /* make sure jobs in creation don't clog queue */
4e969be0
EA
638 w->w_pri = 0x7fffffff;
639 w->w_ctime = 0;
4ff794a3 640
81b7d258 641 /* extract useful information */
4e969be0 642 i = NEED_P | NEED_T;
d6c28d1a
EA
643 if (QueueLimitSender != NULL)
644 i |= NEED_S;
645 if (QueueLimitRecipient != NULL)
646 i |= NEED_R;
4e969be0 647 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 648 {
8ff78b51 649 extern long atol();
d6c28d1a 650 extern bool strcontainedin();
8ff78b51 651
2e3062fe 652 switch (lbuf[0])
81b7d258 653 {
2e3062fe 654 case 'P':
4e969be0
EA
655 w->w_pri = atol(&lbuf[1]);
656 i &= ~NEED_P;
2e3062fe 657 break;
f746582a
EA
658
659 case 'T':
4e969be0
EA
660 w->w_ctime = atol(&lbuf[1]);
661 i &= ~NEED_T;
f746582a 662 break;
d6c28d1a
EA
663
664 case 'R':
665 if (QueueLimitRecipient != NULL &&
666 strcontainedin(QueueLimitRecipient, &lbuf[1]))
667 i &= ~NEED_R;
668 break;
669
670 case 'S':
671 if (QueueLimitSender != NULL &&
672 strcontainedin(QueueLimitSender, &lbuf[1]))
673 i &= ~NEED_S;
674 break;
81b7d258
EA
675 }
676 }
81b7d258 677 (void) fclose(cf);
4bc44f60 678
d6c28d1a
EA
679 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
680 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
681 {
682 /* don't even bother sorting this job in */
683 wn--;
684 }
81b7d258 685 }
ccd1d833 686 (void) closedir(f);
bd0712bd 687 wn++;
81b7d258
EA
688
689 /*
690 ** Sort the work directory.
691 */
692
4e969be0 693 qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
81b7d258
EA
694
695 /*
696 ** Convert the work list into canonical form.
7338e3d4 697 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
698 */
699
a0225d08 700 WorkQ = NULL;
4e969be0 701 for (i = min(wn, QUEUESIZE); --i >= 0; )
81b7d258
EA
702 {
703 w = (WORK *) xalloc(sizeof *w);
704 w->w_name = wlist[i].w_name;
81b7d258 705 w->w_pri = wlist[i].w_pri;
f746582a 706 w->w_ctime = wlist[i].w_ctime;
a0225d08
EA
707 w->w_next = WorkQ;
708 WorkQ = w;
81b7d258
EA
709 }
710
9678c96d 711 if (tTd(40, 1))
81b7d258
EA
712 {
713 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 714 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 715 }
0490b7d7 716
bd0712bd 717 return (wn);
81b7d258
EA
718}
719\f/*
9678c96d 720** WORKCMPF -- compare function for ordering work.
81b7d258
EA
721**
722** Parameters:
723** a -- the first argument.
724** b -- the second argument.
725**
726** Returns:
a0225d08
EA
727** -1 if a < b
728** 0 if a == b
729** +1 if a > b
81b7d258
EA
730**
731** Side Effects:
732** none.
733*/
734
81b7d258 735workcmpf(a, b)
9ccf54c4
EA
736 register WORK *a;
737 register WORK *b;
81b7d258 738{
abccefc9
EA
739 long pa = a->w_pri;
740 long pb = b->w_pri;
2e3062fe
EA
741
742 if (pa == pb)
81b7d258 743 return (0);
2e3062fe 744 else if (pa > pb)
e65b95c4 745 return (1);
a0225d08
EA
746 else
747 return (-1);
81b7d258
EA
748}
749\f/*
750** DOWORK -- do a work request.
751**
752** Parameters:
a7dc53bd
EA
753** id -- the ID of the job to run.
754** forkflag -- if set, run this in background.
f5303697
EA
755** requeueflag -- if set, reinstantiate the queue quickly.
756** This is used when expanding aliases in the queue.
8d00c219
EA
757** If forkflag is also set, it doesn't wait for the
758** child.
a7dc53bd 759** e - the envelope in which to run it.
81b7d258
EA
760**
761** Returns:
762** none.
763**
764** Side Effects:
765** The work request is satisfied if possible.
766*/
767
f5303697 768dowork(id, forkflag, requeueflag, e)
a7dc53bd
EA
769 char *id;
770 bool forkflag;
f5303697 771 bool requeueflag;
a4076aed 772 register ENVELOPE *e;
81b7d258
EA
773{
774 register int i;
3620ad97 775 extern bool readqf();
81b7d258 776
9678c96d 777 if (tTd(40, 1))
a7dc53bd 778 printf("dowork(%s)\n", id);
81b7d258 779
2e3062fe
EA
780 /*
781 ** Fork for work.
782 */
783
a7dc53bd 784 if (forkflag)
2e3062fe
EA
785 {
786 i = fork();
787 if (i < 0)
788 {
789 syserr("dowork: cannot fork");
790 return;
791 }
792 }
793 else
794 {
795 i = 0;
796 }
797
81b7d258
EA
798 if (i == 0)
799 {
800 /*
801 ** CHILD
6bbaf971
EA
802 ** Lock the control file to avoid duplicate deliveries.
803 ** Then run the file as though we had just read it.
68f0b54c
EA
804 ** We save an idea of the temporary name so we
805 ** can recover on interrupt.
81b7d258
EA
806 */
807
9416f3a0 808 /* set basic modes, etc. */
37eaaadb 809 (void) alarm(0);
a4076aed 810 clearenvelope(e, FALSE);
c2bdb1dd 811 e->e_flags |= EF_QUEUERUN;
8c8e8e94 812 e->e_errormode = EM_MAIL;
a7dc53bd 813 e->e_id = id;
36a4e219 814# ifdef LOG
68f7099c 815 if (LogLevel > 76)
a4076aed 816 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 817 getpid());
f3d8f6d6 818# endif /* LOG */
9416f3a0
EA
819
820 /* don't use the headers from sendmail.cf... */
a4076aed 821 e->e_header = NULL;
9416f3a0 822
3620ad97 823 /* read the queue control file -- return if locked */
a4076aed 824 if (!readqf(e))
dd1fe05b 825 {
a7dc53bd
EA
826 if (tTd(40, 4))
827 printf("readqf(%s) failed\n", e->e_id);
828 if (forkflag)
2e3062fe
EA
829 exit(EX_OK);
830 else
831 return;
dd1fe05b 832 }
dd1fe05b 833
a4076aed 834 e->e_flags |= EF_INQUEUE;
959cf51d 835 eatheader(e, requeueflag);
dd1fe05b 836
f5303697
EA
837 if (requeueflag)
838 queueup(e, TRUE, FALSE);
839
dd1fe05b 840 /* do the delivery */
e678ee95 841 sendall(e, SM_DELIVER);
dd1fe05b 842
dd1fe05b 843 /* finish up and exit */
a7dc53bd 844 if (forkflag)
2e3062fe
EA
845 finis();
846 else
a4076aed 847 dropenvelope(e);
81b7d258 848 }
8d00c219 849 else if (!requeueflag)
2e3062fe
EA
850 {
851 /*
852 ** Parent -- pick up results.
853 */
81b7d258 854
2e3062fe
EA
855 errno = 0;
856 (void) waitfor(i);
857 }
81b7d258
EA
858}
859\f/*
860** READQF -- read queue file and set up environment.
861**
862** Parameters:
7338e3d4 863** e -- the envelope of the job to run.
81b7d258
EA
864**
865** Returns:
3620ad97
EA
866** TRUE if it successfully read the queue file.
867** FALSE otherwise.
81b7d258
EA
868**
869** Side Effects:
3620ad97 870** The queue file is returned locked.
81b7d258
EA
871*/
872
3620ad97
EA
873bool
874readqf(e)
7338e3d4 875 register ENVELOPE *e;
81b7d258 876{
11e3f8b5 877 register FILE *qfp;
d2213d6c 878 ADDRESS *ctladdr;
dcbc04c7 879 struct stat st;
07b49560 880 char *bp;
e678ee95 881 char qf[20];
07b49560 882 char buf[MAXLINE];
8ff78b51 883 extern long atol();
d2213d6c 884 extern ADDRESS *setctluser();
abae7b2d 885 extern ADDRESS *sendto();
81b7d258 886
81b7d258
EA
887 /*
888 ** Read and process the file.
889 */
890
e678ee95 891 strcpy(qf, queuename(e, 'q'));
76b607b2 892 qfp = fopen(qf, "r+");
11e3f8b5
EA
893 if (qfp == NULL)
894 {
a7dc53bd
EA
895 if (tTd(40, 8))
896 printf("readqf(%s): fopen failure (%s)\n",
897 qf, errstring(errno));
3f9ac8ea
RA
898 if (errno != ENOENT)
899 syserr("readqf: no control file %s", qf);
3620ad97 900 return FALSE;
3f9ac8ea
RA
901 }
902
dcbc04c7
EA
903 /*
904 ** Check the queue file for plausibility to avoid attacks.
905 */
906
907 if (fstat(fileno(qfp), &st) < 0)
908 {
909 /* must have been being processed by someone else */
a7dc53bd
EA
910 if (tTd(40, 8))
911 printf("readqf(%s): fstat failure (%s)\n",
912 qf, errstring(errno));
dcbc04c7
EA
913 fclose(qfp);
914 return FALSE;
915 }
916
07b49560 917 if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode)
dcbc04c7
EA
918 {
919# ifdef LOG
920 if (LogLevel > 0)
921 {
922 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
923 e->e_id, st.st_uid, st.st_mode);
924 }
f3d8f6d6 925# endif /* LOG */
a7dc53bd
EA
926 if (tTd(40, 8))
927 printf("readqf(%s): bogus file\n", qf);
dcbc04c7
EA
928 fclose(qfp);
929 return FALSE;
930 }
931
f8a31c8e 932 if (!lockfile(fileno(qfp), qf, LOCK_EX|LOCK_NB))
3f9ac8ea 933 {
f8a31c8e 934 /* being processed by another queuer */
a7dc53bd
EA
935 if (tTd(40, 8))
936 printf("readqf(%s): locked\n", qf);
f8a31c8e
EA
937 if (Verbose)
938 printf("%s: locked\n", e->e_id);
3620ad97 939# ifdef LOG
f8a31c8e
EA
940 if (LogLevel > 19)
941 syslog(LOG_DEBUG, "%s: locked", e->e_id);
f3d8f6d6 942# endif /* LOG */
3f9ac8ea 943 (void) fclose(qfp);
3620ad97 944 return FALSE;
11e3f8b5 945 }
3f9ac8ea 946
c87034b7
EA
947 if (st.st_size == 0)
948 {
949 /* must be a bogus file -- just remove it */
950 (void) unlink(qf);
951 fclose(qfp);
952 return FALSE;
953 }
954
3620ad97
EA
955 /* save this lock */
956 e->e_lockfp = qfp;
957
3f9ac8ea 958 /* do basic system initialization */
a4076aed 959 initsys(e);
3f9ac8ea 960
11e3f8b5 961 FileName = qf;
560a80d9 962 LineNumber = 0;
3620ad97 963 if (Verbose)
7338e3d4 964 printf("\nRunning %s\n", e->e_id);
d2213d6c 965 ctladdr = NULL;
07b49560 966 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 967 {
c2bdb1dd 968 register char *p;
65b5adb6
EA
969 struct stat st;
970
795590e2 971 if (tTd(40, 4))
07b49560
EA
972 printf("+++++ %s\n", bp);
973 switch (bp[0])
81b7d258 974 {
3fbc69d6 975 case 'C': /* specify controlling user */
07b49560 976 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
977 break;
978
81b7d258 979 case 'R': /* specify recipient */
abae7b2d 980 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
981 break;
982
4e969be0 983 case 'E': /* specify error recipient */
1c7897ef 984 (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e);
4e969be0
EA
985 break;
986
81b7d258 987 case 'H': /* header */
07b49560 988 (void) chompheader(&bp[1], FALSE, e);
81b7d258
EA
989 break;
990
baa0c390 991 case 'M': /* message */
07b49560 992 e->e_message = newstr(&bp[1]);
baa0c390
EA
993 break;
994
81b7d258 995 case 'S': /* sender */
4a2da288 996 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
997 break;
998
96bfbc2c
EA
999 case 'B': /* body type */
1000 e->e_bodytype = newstr(&bp[1]);
1001 break;
1002
81b7d258 1003 case 'D': /* data file name */
07b49560 1004 e->e_df = newstr(&bp[1]);
912acb74
EA
1005 e->e_dfp = fopen(e->e_df, "r");
1006 if (e->e_dfp == NULL)
68f7099c 1007 {
7338e3d4 1008 syserr("readqf: cannot open %s", e->e_df);
68f7099c
EA
1009 e->e_msgsize = -1;
1010 }
1011 else if (fstat(fileno(e->e_dfp), &st) >= 0)
65b5adb6 1012 e->e_msgsize = st.st_size;
81b7d258
EA
1013 break;
1014
96476cab 1015 case 'T': /* init time */
07b49560 1016 e->e_ctime = atol(&bp[1]);
81b7d258
EA
1017 break;
1018
aba51985 1019 case 'P': /* message priority */
07b49560 1020 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
1021 break;
1022
c2bdb1dd
EA
1023 case 'F': /* flag bits */
1024 for (p = &bp[1]; *p != '\0'; p++)
1025 {
1026 switch (*p)
1027 {
1028 case 'w': /* warning sent */
1029 e->e_flags |= EF_WARNING;
1030 break;
1031
1032 case 'r': /* response */
1033 e->e_flags |= EF_RESPONSE;
1034 break;
1035 }
1036 }
1037 break;
1038
22293c34 1039 case '$': /* define macro */
07b49560 1040 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
1041 break;
1042
2e3062fe
EA
1043 case '\0': /* blank line; ignore */
1044 break;
1045
81b7d258 1046 default:
ef3bc6b1 1047 syserr("readqf: bad line \"%s\"", e->e_id,
07b49560 1048 LineNumber, bp);
81b7d258
EA
1049 break;
1050 }
07b49560
EA
1051
1052 if (bp != buf)
1053 free(bp);
81b7d258 1054 }
7338e3d4
EA
1055
1056 FileName = NULL;
2e3062fe
EA
1057
1058 /*
1059 ** If we haven't read any lines, this queue file is empty.
1060 ** Arrange to remove it without referencing any null pointers.
1061 */
1062
1063 if (LineNumber == 0)
1064 {
1065 errno = 0;
1066 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1067 }
3620ad97 1068 return TRUE;
81b7d258
EA
1069}
1070\f/*
64912e7e
EA
1071** PRINTQUEUE -- print out a representation of the mail queue
1072**
1073** Parameters:
1074** none.
1075**
1076** Returns:
1077** none.
1078**
1079** Side Effects:
1080** Prints a listing of the mail queue on the standard output.
1081*/
1082
1083printqueue()
1084{
1085 register WORK *w;
1086 FILE *f;
0490b7d7 1087 int nrequests;
64912e7e
EA
1088 char buf[MAXLINE];
1089
374579b6
EA
1090 /*
1091 ** Check for permission to print the queue
1092 */
1093
3afbc0f1 1094 if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && getuid() != 0)
374579b6
EA
1095 {
1096 struct stat st;
3afbc0f1
EA
1097# ifdef NGROUPS
1098 int n;
1099 int gidset[NGROUPS];
1100# endif
374579b6 1101
7c8b3fd4 1102 if (stat(QueueDir, &st) < 0)
374579b6
EA
1103 {
1104 syserr("Cannot stat %s", QueueDir);
1105 return;
1106 }
3afbc0f1
EA
1107# ifdef NGROUPS
1108 n = getgroups(NGROUPS, gidset);
1109 while (--n >= 0)
1110 {
1111 if (gidset[n] == st.st_gid)
1112 break;
1113 }
1114 if (n < 0)
1115# else
374579b6 1116 if (getgid() != st.st_gid)
3afbc0f1 1117# endif
374579b6
EA
1118 {
1119 usrerr("510 You are not permitted to see the queue");
1120 setstat(EX_NOPERM);
1121 return;
1122 }
1123 }
1124
64912e7e
EA
1125 /*
1126 ** Read and order the queue.
1127 */
1128
2e3062fe 1129 nrequests = orderq(TRUE);
64912e7e
EA
1130
1131 /*
1132 ** Print the work list that we have read.
1133 */
1134
1135 /* first see if there is anything */
0490b7d7 1136 if (nrequests <= 0)
64912e7e 1137 {
0490b7d7 1138 printf("Mail queue is empty\n");
64912e7e
EA
1139 return;
1140 }
1141
3620ad97 1142 CurrentLA = getla(); /* get load average */
3f9ac8ea 1143
d7b5594c 1144 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
4e969be0
EA
1145 if (nrequests > QUEUESIZE)
1146 printf(", only %d printed", QUEUESIZE);
f4b05990 1147 if (Verbose)
fbab5052 1148 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1149 else
fbab5052 1150 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1151 for (w = WorkQ; w != NULL; w = w->w_next)
1152 {
1153 struct stat st;
0490b7d7
EA
1154 auto time_t submittime = 0;
1155 long dfsize = -1;
c2bdb1dd 1156 int flags = 0;
baa0c390 1157 char message[MAXLINE];
96bfbc2c 1158 char bodytype[MAXNAME];
64912e7e 1159
560a80d9
EA
1160 f = fopen(w->w_name, "r");
1161 if (f == NULL)
1162 {
1163 errno = 0;
1164 continue;
1165 }
8eaf308b 1166 printf("%8s", w->w_name + 2);
f8a31c8e 1167 if (!lockfile(fileno(f), w->w_name, LOCK_SH|LOCK_NB))
0490b7d7 1168 printf("*");
abccefc9 1169 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1170 printf("X");
0490b7d7
EA
1171 else
1172 printf(" ");
1173 errno = 0;
560a80d9 1174
96bfbc2c 1175 message[0] = bodytype[0] = '\0';
64912e7e
EA
1176 while (fgets(buf, sizeof buf, f) != NULL)
1177 {
22293c34 1178 register int i;
c2bdb1dd 1179 register char *p;
22293c34 1180
64912e7e
EA
1181 fixcrlf(buf, TRUE);
1182 switch (buf[0])
1183 {
baa0c390 1184 case 'M': /* error message */
22293c34 1185 if ((i = strlen(&buf[1])) >= sizeof message)
c2bdb1dd 1186 i = sizeof message - 1;
22293c34
EA
1187 bcopy(&buf[1], message, i);
1188 message[i] = '\0';
baa0c390
EA
1189 break;
1190
96bfbc2c
EA
1191 case 'B': /* body type */
1192 if ((i = strlen(&buf[1])) >= sizeof bodytype)
1193 i = sizeof bodytype - 1;
1194 bcopy(&buf[1], bodytype, i);
1195 bodytype[i] = '\0';
1196 break;
1197
64912e7e 1198 case 'S': /* sender name */
f4b05990 1199 if (Verbose)
c2bdb1dd
EA
1200 printf("%8ld %10ld%c%.12s %.38s",
1201 dfsize,
1202 w->w_pri,
1203 bitset(EF_WARNING, flags) ? '+' : ' ',
1204 ctime(&submittime) + 4,
f4b05990
EA
1205 &buf[1]);
1206 else
1207 printf("%8ld %.16s %.45s", dfsize,
1208 ctime(&submittime), &buf[1]);
96bfbc2c
EA
1209 if (message[0] != '\0' || bodytype[0] != '\0')
1210 {
1211 printf("\n %10.10s", bodytype);
1212 if (message[0] != '\0')
1213 printf(" (%.60s)", message);
1214 }
64912e7e 1215 break;
3620ad97 1216
3fbc69d6 1217 case 'C': /* controlling user */
d2213d6c 1218 if (Verbose)
fbab5052
EA
1219 printf("\n\t\t\t\t (---%.34s---)",
1220 &buf[1]);
3fbc69d6 1221 break;
64912e7e
EA
1222
1223 case 'R': /* recipient name */
f4b05990 1224 if (Verbose)
fbab5052 1225 printf("\n\t\t\t\t\t %.38s", &buf[1]);
f4b05990 1226 else
fbab5052 1227 printf("\n\t\t\t\t %.45s", &buf[1]);
64912e7e
EA
1228 break;
1229
1230 case 'T': /* creation time */
2e3062fe 1231 submittime = atol(&buf[1]);
0490b7d7
EA
1232 break;
1233
1234 case 'D': /* data file name */
1235 if (stat(&buf[1], &st) >= 0)
1236 dfsize = st.st_size;
64912e7e 1237 break;
c2bdb1dd
EA
1238
1239 case 'F': /* flag bits */
1240 for (p = &buf[1]; *p != '\0'; p++)
1241 {
1242 switch (*p)
1243 {
1244 case 'w':
1245 flags |= EF_WARNING;
1246 break;
1247 }
1248 }
64912e7e
EA
1249 }
1250 }
0490b7d7
EA
1251 if (submittime == (time_t) 0)
1252 printf(" (no control file)");
64912e7e 1253 printf("\n");
0e306e7f 1254 (void) fclose(f);
64912e7e
EA
1255 }
1256}
884a20cb 1257
f3d8f6d6 1258# endif /* QUEUE */
560a80d9
EA
1259\f/*
1260** QUEUENAME -- build a file name in the queue directory for this envelope.
1261**
1262** Assigns an id code if one does not already exist.
1263** This code is very careful to avoid trashing existing files
1264** under any circumstances.
560a80d9
EA
1265**
1266** Parameters:
1267** e -- envelope to build it in/from.
1268** type -- the file type, used as the first character
1269** of the file name.
1270**
1271** Returns:
1272** a pointer to the new file name (in a static buffer).
1273**
1274** Side Effects:
3620ad97
EA
1275** If no id code is already assigned, queuename will
1276** assign an id code, create a qf file, and leave a
1277** locked, open-for-write file pointer in the envelope.
560a80d9
EA
1278*/
1279
1280char *
1281queuename(e, type)
1282 register ENVELOPE *e;
ef3bc6b1 1283 int type;
560a80d9 1284{
560a80d9 1285 static int pid = -1;
e3bb0d32
EA
1286 static char c0;
1287 static char c1;
1288 static char c2;
fbab5052
EA
1289 time_t now;
1290 struct tm *tm;
f8a31c8e 1291 static char buf[MAXNAME];
560a80d9
EA
1292
1293 if (e->e_id == NULL)
1294 {
1295 char qf[20];
560a80d9
EA
1296
1297 /* find a unique id */
1298 if (pid != getpid())
1299 {
1300 /* new process -- start back at "AA" */
1301 pid = getpid();
fbab5052
EA
1302 now = curtime();
1303 tm = localtime(&now);
1304 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1305 c1 = 'A';
1306 c2 = 'A' - 1;
1307 }
fbab5052 1308 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1309
1310 while (c1 < '~' || c2 < 'Z')
1311 {
1312 int i;
1313
1314 if (c2 >= 'Z')
1315 {
1316 c1++;
1317 c2 = 'A' - 1;
1318 }
fbab5052
EA
1319 qf[3] = c1;
1320 qf[4] = ++c2;
560a80d9 1321 if (tTd(7, 20))
3f9ac8ea 1322 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1323
3f9ac8ea 1324 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1325 if (i < 0)
1326 {
1327 if (errno == EEXIST)
1328 continue;
1329 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1330 qf, QueueDir);
1331 exit(EX_UNAVAILABLE);
1332 }
f8a31c8e 1333 if (lockfile(i, qf, LOCK_EX|LOCK_NB))
3620ad97
EA
1334 {
1335 e->e_lockfp = fdopen(i, "w");
bb09c502 1336 break;
3f9ac8ea 1337 }
3620ad97
EA
1338
1339 /* a reader got the file; abandon it and try again */
1340 (void) close(i);
560a80d9
EA
1341 }
1342 if (c1 >= '~' && c2 >= 'Z')
1343 {
1344 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1345 qf, QueueDir);
1346 exit(EX_OSERR);
1347 }
1348 e->e_id = newstr(&qf[2]);
1349 define('i', e->e_id, e);
560a80d9
EA
1350 if (tTd(7, 1))
1351 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1352# ifdef LOG
68f7099c 1353 if (LogLevel > 93)
560a80d9 1354 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1355# endif /* LOG */
560a80d9
EA
1356 }
1357
1358 if (type == '\0')
1359 return (NULL);
1360 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1361 if (tTd(7, 2))
1362 printf("queuename: %s\n", buf);
560a80d9
EA
1363 return (buf);
1364}
1365\f/*
1366** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1367**
1368** Parameters:
1369** e -- the envelope to unlock.
1370**
1371** Returns:
1372** none
1373**
1374** Side Effects:
1375** unlocks the queue for `e'.
1376*/
1377
1378unlockqueue(e)
1379 ENVELOPE *e;
1380{
bc854e30
EA
1381 if (tTd(51, 4))
1382 printf("unlockqueue(%s)\n", e->e_id);
1383
3620ad97
EA
1384 /* if there is a lock file in the envelope, close it */
1385 if (e->e_lockfp != NULL)
bc854e30 1386 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1387 e->e_lockfp = NULL;
1388
32061c38
EA
1389 /* don't create a queue id if we don't already have one */
1390 if (e->e_id == NULL)
1391 return;
1392
560a80d9 1393 /* remove the transcript */
560a80d9 1394# ifdef LOG
68f7099c 1395 if (LogLevel > 87)
560a80d9 1396 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1397# endif /* LOG */
bc854e30 1398 if (!tTd(51, 104))
560a80d9
EA
1399 xunlink(queuename(e, 'x'));
1400
560a80d9 1401}
3fbc69d6 1402\f/*
d2213d6c 1403** SETCTLUSER -- create a controlling address
3fbc69d6 1404**
d2213d6c
EA
1405** Create a fake "address" given only a local login name; this is
1406** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1407**
1408** Parameters:
d2213d6c 1409** user -- the user name of the controlling user.
3fbc69d6
KB
1410**
1411** Returns:
d2213d6c 1412** An address descriptor for the controlling user.
3fbc69d6
KB
1413**
1414** Side Effects:
1415** none.
1416*/
1417
d2213d6c
EA
1418ADDRESS *
1419setctluser(user)
1420 char *user;
3fbc69d6 1421{
d2213d6c 1422 register ADDRESS *a;
3fbc69d6 1423 struct passwd *pw;
9cdb0b30 1424 char *p;
3fbc69d6
KB
1425
1426 /*
d2213d6c 1427 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1428 */
1429
f7894324
EA
1430 if (user == NULL)
1431 user = "";
3fbc69d6
KB
1432
1433 /*
d2213d6c 1434 ** Set up addr fields for controlling user.
3fbc69d6
KB
1435 */
1436
d2213d6c
EA
1437 a = (ADDRESS *) xalloc(sizeof *a);
1438 bzero((char *) a, sizeof *a);
9cdb0b30
EA
1439
1440 p = strchr(user, ':');
1441 if (p != NULL)
1442 *p++ = '\0';
f7894324 1443 if (*user != '\0' && (pw = getpwnam(user)) != NULL)
3fbc69d6 1444 {
3fbc69d6
KB
1445 a->q_home = newstr(pw->pw_dir);
1446 a->q_uid = pw->pw_uid;
1447 a->q_gid = pw->pw_gid;
6e99f903 1448 a->q_user = newstr(user);
f7894324 1449 a->q_flags |= QGOODUID;
3fbc69d6
KB
1450 }
1451 else
1452 {
6e99f903 1453 a->q_user = newstr(DefUser);
3fbc69d6
KB
1454 }
1455
f7894324 1456 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1457 a->q_mailer = LocalMailer;
9cdb0b30
EA
1458 if (p == NULL)
1459 a->q_paddr = a->q_user;
1460 else
1461 a->q_paddr = newstr(p);
d2213d6c 1462 return a;
3fbc69d6 1463}