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