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