don't core dump on "struct { a y; a z; };".
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
81b7d258
EA
1# include "sendmail.h"
2# include <sys/stat.h>
a2cb9a08 3# include <sys/dir.h>
aba51985 4# include <signal.h>
81b7d258
EA
5# include <errno.h>
6
884a20cb 7# ifndef QUEUE
11e3f8b5 8SCCSID(@(#)queue.c 4.4 %G% (no queueing));
884a20cb
EA
9# else QUEUE
10
11e3f8b5 11SCCSID(@(#)queue.c 4.4 %G%);
81b7d258
EA
12
13/*
7338e3d4
EA
14** Work queue.
15*/
16
17struct work
18{
19 char *w_name; /* name of control file */
20 long w_pri; /* priority of message, see below */
21 struct work *w_next; /* next in queue */
22};
23
24typedef struct work WORK;
25
26WORK *WorkQ; /* queue of things to be done */
27\f/*
81b7d258
EA
28** QUEUEUP -- queue a message up for future transmission.
29**
81b7d258 30** Parameters:
dd1fe05b 31** e -- the envelope to queue up.
d0bd03ce
EA
32** queueall -- if TRUE, queue all addresses, rather than
33** just those with the QQUEUEUP flag set.
7338e3d4 34** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
35**
36** Returns:
37** none.
38**
39** Side Effects:
7338e3d4 40** The current request are saved in a control file.
81b7d258
EA
41*/
42
7338e3d4 43queueup(e, queueall, announce)
dd1fe05b 44 register ENVELOPE *e;
d0bd03ce 45 bool queueall;
7338e3d4 46 bool announce;
81b7d258 47{
2cce0c26
EA
48 char *tf;
49 char *qf;
9416f3a0 50 char buf[MAXLINE];
2cce0c26 51 register FILE *tfp;
81b7d258 52 register HDR *h;
d4f42161 53 register ADDRESS *q;
4db45bf1 54 MAILER nullmailer;
81b7d258 55
9ccf54c4 56 /*
11e3f8b5 57 ** Create control file.
9ccf54c4 58 */
81b7d258 59
11e3f8b5
EA
60 tf = newstr(queuename(e, 't'));
61 tfp = fopen(tf, "w");
2cce0c26 62 if (tfp == NULL)
81b7d258 63 {
11e3f8b5
EA
64 syserr("queueup: cannot create temp file %s", tf);
65 return;
81b7d258 66 }
11e3f8b5 67 (void) chmod(tf, FileMode);
81b7d258
EA
68
69# ifdef DEBUG
9678c96d 70 if (tTd(40, 1))
560a80d9 71 printf("queueing %s\n", e->e_id);
81b7d258
EA
72# endif DEBUG
73
dd1fe05b
EA
74 /*
75 ** If there is no data file yet, create one.
76 */
77
78 if (e->e_df == NULL)
79 {
80 register FILE *dfp;
80482eb5 81 extern putbody();
dd1fe05b 82
2cce0c26 83 e->e_df = newstr(queuename(e, 'd'));
dd1fe05b
EA
84 dfp = fopen(e->e_df, "w");
85 if (dfp == NULL)
86 {
87 syserr("queueup: cannot create %s", e->e_df);
2cce0c26 88 (void) fclose(tfp);
dd1fe05b
EA
89 return;
90 }
6db97a2f 91 (void) chmod(e->e_df, FileMode);
4db45bf1 92 (*e->e_putbody)(dfp, ProgMailer, e);
f9566d23 93 (void) fclose(dfp);
80482eb5 94 e->e_putbody = putbody;
dd1fe05b
EA
95 }
96
81b7d258
EA
97 /*
98 ** Output future work requests.
7338e3d4 99 ** Priority should be first, since it is read by orderq.
81b7d258
EA
100 */
101
7338e3d4
EA
102 /* output message priority */
103 fprintf(tfp, "P%ld\n", e->e_msgpriority);
104
64912e7e
EA
105 /* output creation time */
106 fprintf(tfp, "T%ld\n", e->e_ctime);
107
81b7d258 108 /* output name of data file */
2cce0c26 109 fprintf(tfp, "D%s\n", e->e_df);
81b7d258 110
baa0c390
EA
111 /* message from envelope, if it exists */
112 if (e->e_message != NULL)
113 fprintf(tfp, "M%s\n", e->e_message);
114
81b7d258 115 /* output name of sender */
2cce0c26 116 fprintf(tfp, "S%s\n", e->e_from.q_paddr);
81b7d258 117
81b7d258 118 /* output list of recipient addresses */
dd1fe05b 119 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 120 {
9416f3a0
EA
121 if (queueall ? !bitset(QDONTSEND, q->q_flags) :
122 bitset(QQUEUEUP, q->q_flags))
4d237f16 123 {
2cce0c26 124 fprintf(tfp, "R%s\n", q->q_paddr);
7338e3d4
EA
125 if (announce)
126 {
127 e->e_to = q->q_paddr;
128 message(Arpa_Info, "queued");
129 if (LogLevel > 4)
130 logdelivery("queued");
131 e->e_to = NULL;
132 }
b9accadd
EA
133#ifdef DEBUG
134 if (tTd(40, 1))
135 {
136 printf("queueing ");
137 printaddr(q, FALSE);
138 }
139#endif DEBUG
4d237f16 140 }
81b7d258
EA
141 }
142
7338e3d4
EA
143 /*
144 ** Output headers for this message.
145 ** Expand macros completely here. Queue run will deal with
146 ** everything as absolute headers.
147 ** All headers that must be relative to the recipient
148 ** can be cracked later.
4db45bf1
EA
149 ** We set up a "null mailer" -- i.e., a mailer that will have
150 ** no effect on the addresses as they are output.
7338e3d4
EA
151 */
152
1dbda134 153 bzero((char *) &nullmailer, sizeof nullmailer);
4db45bf1 154 nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;
281ef7f0 155 nullmailer.m_eol = "\n";
4db45bf1 156
a73ae8ac 157 define('g', "\001f", e);
dd1fe05b 158 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 159 {
1dbda134
EA
160 extern bool bitzerop();
161
83e9910e 162 /* don't output null headers */
81b7d258
EA
163 if (h->h_value == NULL || h->h_value[0] == '\0')
164 continue;
83e9910e
EA
165
166 /* don't output resent headers on non-resent messages */
167 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
168 continue;
169
170 /* output this header */
2cce0c26 171 fprintf(tfp, "H");
83e9910e
EA
172
173 /* if conditional, output the set of conditions */
1dbda134
EA
174 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
175 {
176 int j;
177
178 putc('?', tfp);
179 for (j = '\0'; j <= '\177'; j++)
180 if (bitnset(j, h->h_mflags))
181 putc(j, tfp);
182 putc('?', tfp);
183 }
83e9910e
EA
184
185 /* output the header: expand macros, convert addresses */
9416f3a0
EA
186 if (bitset(H_DEFAULT, h->h_flags))
187 {
188 (void) expand(h->h_value, buf, &buf[sizeof buf], e);
3ba0846a 189 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 190 }
4d237f16 191 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d
EA
192 {
193 commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
4db45bf1 194 &nullmailer);
611b763d 195 }
4d237f16
EA
196 else
197 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
198 }
199
200 /*
201 ** Clean up.
202 */
203
11e3f8b5 204 (void) fclose(tfp);
2cce0c26 205 qf = queuename(e, 'q');
560a80d9
EA
206 if (tf != NULL)
207 {
560a80d9
EA
208 holdsigs();
209 (void) unlink(qf);
210 if (link(tf, qf) < 0)
211 syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df);
212 else
213 (void) unlink(tf);
214 rlsesigs();
560a80d9 215 }
1a13ccd8 216
9678c96d
EA
217# ifdef LOG
218 /* save log info */
a8f5bbff
EA
219 if (LogLevel > 15)
220 syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
9678c96d 221# endif LOG
81b7d258
EA
222}
223\f/*
224** RUNQUEUE -- run the jobs in the queue.
225**
226** Gets the stuff out of the queue in some presumably logical
227** order and processes them.
228**
229** Parameters:
230** none.
231**
232** Returns:
233** none.
234**
235** Side Effects:
236** runs things in the mail queue.
237*/
238
2cf55cb7
EA
239runqueue(forkflag)
240 bool forkflag;
81b7d258 241{
b6dffdf5
EA
242 /*
243 ** See if we want to go off and do other useful work.
244 */
2cf55cb7
EA
245
246 if (forkflag)
247 {
6d06102a
EA
248 int pid;
249
250 pid = dofork();
251 if (pid != 0)
2cf55cb7 252 {
6d06102a 253 /* parent -- pick up intermediate zombie */
7338e3d4 254 (void) waitfor(pid);
c4442979 255 if (QueueIntvl != 0)
611b763d 256 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
257 return;
258 }
6d06102a
EA
259 /* child -- double fork */
260 if (fork() != 0)
261 exit(EX_OK);
b6dffdf5 262 }
36a4e219
EA
263# ifdef LOG
264 if (LogLevel > 11)
6d06102a 265 syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
36a4e219 266# endif LOG
81b7d258 267
eb8af3ce
EA
268 /*
269 ** Release any resources used by the daemon code.
270 */
271
272# ifdef DAEMON
273 clrdaemon();
274# endif DAEMON
275
b6dffdf5
EA
276 /*
277 ** Start making passes through the queue.
278 ** First, read and sort the entire queue.
279 ** Then, process the work in that order.
280 ** But if you take too long, start over.
b6dffdf5 281 */
81b7d258 282
6d06102a 283 /* order the existing work requests */
0490b7d7 284 (void) orderq();
291fa573 285
6d06102a
EA
286 /* process them once at a time */
287 while (WorkQ != NULL)
2cf55cb7 288 {
6d06102a 289 WORK *w = WorkQ;
2cf55cb7 290
6d06102a
EA
291 WorkQ = WorkQ->w_next;
292 dowork(w);
293 free(w->w_name);
294 free((char *) w);
2cf55cb7 295 }
6d06102a 296 finis();
aba51985
EA
297}
298\f/*
81b7d258
EA
299** ORDERQ -- order the work queue.
300**
301** Parameters:
302** none.
303**
304** Returns:
e65b95c4
EA
305** The number of request in the queue (not necessarily
306** the number of requests in WorkQ however).
81b7d258
EA
307**
308** Side Effects:
309** Sets WorkQ to the queue of available work, in order.
310*/
311
312# define WLSIZE 120 /* max size of worklist per sort */
313
38d3b461
EA
314# ifndef DIR
315# define DIR FILE
316# define direct dir
317# define opendir(d) fopen(d, "r")
07a8f29b 318# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
319static struct dir dbuf;
320# define closedir(f) fclose(f)
321# endif DIR
322
81b7d258
EA
323orderq()
324{
ccd1d833 325 register struct direct *d;
81b7d258
EA
326 register WORK *w;
327 register WORK **wp; /* parent of w */
ccd1d833 328 DIR *f;
81b7d258 329 register int i;
e65b95c4 330 WORK wlist[WLSIZE+1];
0490b7d7 331 int wn = -1;
81b7d258 332 extern workcmpf();
81b7d258
EA
333
334 /* clear out old WorkQ */
335 for (w = WorkQ; w != NULL; )
336 {
337 register WORK *nw = w->w_next;
338
339 WorkQ = nw;
340 free(w->w_name);
341 free((char *) w);
342 w = nw;
343 }
344
345 /* open the queue directory */
6bbaf971 346 f = opendir(".");
81b7d258
EA
347 if (f == NULL)
348 {
6bbaf971 349 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 350 return (0);
81b7d258
EA
351 }
352
353 /*
354 ** Read the work directory.
355 */
356
0490b7d7 357 while ((d = readdir(f)) != NULL)
81b7d258 358 {
81b7d258 359 FILE *cf;
7338e3d4 360 char lbuf[MAXNAME];
81b7d258
EA
361
362 /* is this an interesting entry? */
07a8f29b
EA
363 if (d->d_ino == 0)
364 continue;
365# ifdef DEBUG
366 if (tTd(40, 10))
367 printf("orderq: %12s\n", d->d_name);
368# endif DEBUG
2cce0c26 369 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
370 continue;
371
0490b7d7
EA
372 /* yes -- open control file (if not too many files) */
373 if (++wn >= WLSIZE)
374 continue;
6bbaf971 375 cf = fopen(d->d_name, "r");
81b7d258
EA
376 if (cf == NULL)
377 {
91f69adf
EA
378 /* this may be some random person sending hir msgs */
379 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
380#ifdef DEBUG
381 if (tTd(41, 2))
382 printf("orderq: cannot open %s (%d)\n",
383 d->d_name, errno);
384#endif DEBUG
91f69adf 385 errno = 0;
bd0712bd 386 wn--;
81b7d258
EA
387 continue;
388 }
6bbaf971 389 wlist[wn].w_name = newstr(d->d_name);
81b7d258
EA
390
391 /* extract useful information */
81b7d258
EA
392 while (fgets(lbuf, sizeof lbuf, cf) != NULL)
393 {
7338e3d4 394 if (lbuf[0] == 'P')
81b7d258 395 {
9ccf54c4 396 (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri);
81b7d258
EA
397 break;
398 }
399 }
81b7d258
EA
400 (void) fclose(cf);
401 }
ccd1d833 402 (void) closedir(f);
bd0712bd 403 wn++;
81b7d258
EA
404
405 /*
406 ** Sort the work directory.
407 */
408
e65b95c4 409 qsort(wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf);
81b7d258
EA
410
411 /*
412 ** Convert the work list into canonical form.
7338e3d4 413 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
414 */
415
416 wp = &WorkQ;
e65b95c4 417 for (i = min(wn, WLSIZE); --i >= 0; )
81b7d258
EA
418 {
419 w = (WORK *) xalloc(sizeof *w);
420 w->w_name = wlist[i].w_name;
81b7d258
EA
421 w->w_pri = wlist[i].w_pri;
422 w->w_next = NULL;
423 *wp = w;
424 wp = &w->w_next;
425 }
426
427# ifdef DEBUG
9678c96d 428 if (tTd(40, 1))
81b7d258
EA
429 {
430 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 431 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258
EA
432 }
433# endif DEBUG
0490b7d7 434
bd0712bd 435 return (wn);
81b7d258
EA
436}
437\f/*
9678c96d 438** WORKCMPF -- compare function for ordering work.
81b7d258
EA
439**
440** Parameters:
441** a -- the first argument.
442** b -- the second argument.
443**
444** Returns:
e65b95c4 445** 1 if a < b
81b7d258 446** 0 if a == b
e65b95c4 447** -1 if a > b
81b7d258
EA
448**
449** Side Effects:
450** none.
451*/
452
81b7d258 453workcmpf(a, b)
9ccf54c4
EA
454 register WORK *a;
455 register WORK *b;
81b7d258 456{
9ccf54c4 457 if (a->w_pri == b->w_pri)
81b7d258 458 return (0);
9ccf54c4 459 else if (a->w_pri > b->w_pri)
81b7d258 460 return (-1);
e65b95c4
EA
461 else
462 return (1);
81b7d258
EA
463}
464\f/*
465** DOWORK -- do a work request.
466**
467** Parameters:
468** w -- the work request to be satisfied.
469**
470** Returns:
471** none.
472**
473** Side Effects:
474** The work request is satisfied if possible.
475*/
476
477dowork(w)
478 register WORK *w;
479{
480 register int i;
81b7d258
EA
481
482# ifdef DEBUG
9678c96d 483 if (tTd(40, 1))
9ccf54c4 484 printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
81b7d258
EA
485# endif DEBUG
486
487 /*
488 ** Fork for work.
489 */
490
491 i = fork();
492 if (i < 0)
493 {
494 syserr("dowork: cannot fork");
495 return;
496 }
497
498 if (i == 0)
499 {
500 /*
501 ** CHILD
6bbaf971
EA
502 ** Lock the control file to avoid duplicate deliveries.
503 ** Then run the file as though we had just read it.
68f0b54c
EA
504 ** We save an idea of the temporary name so we
505 ** can recover on interrupt.
81b7d258
EA
506 */
507
9416f3a0 508 /* set basic modes, etc. */
37eaaadb 509 (void) alarm(0);
bcf74f25 510 closexscript(CurEnv);
e6f08ab1 511 CurEnv->e_flags &= ~EF_FATALERRS;
81b7d258 512 QueueRun = TRUE;
7338e3d4 513 ErrorMode = EM_MAIL;
6bbaf971 514 CurEnv->e_id = &w->w_name[2];
36a4e219
EA
515# ifdef LOG
516 if (LogLevel > 11)
291fa573
EA
517 syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
518 getpid());
36a4e219 519# endif LOG
9416f3a0
EA
520
521 /* don't use the headers from sendmail.cf... */
522 CurEnv->e_header = NULL;
9416f3a0 523
560a80d9 524 /* lock the control file during processing */
2cce0c26 525 if (link(w->w_name, queuename(CurEnv, 'l')) < 0)
dd1fe05b 526 {
2cce0c26 527 /* being processed by another queuer */
291fa573
EA
528# ifdef LOG
529 if (LogLevel > 4)
530 syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id);
531# endif LOG
dd1fe05b
EA
532 exit(EX_OK);
533 }
dd1fe05b 534
dd1fe05b 535 /* do basic system initialization */
81b7d258 536 initsys();
dd1fe05b
EA
537
538 /* read the queue control file */
11e3f8b5 539 readqf(CurEnv, TRUE);
e6f08ab1 540 CurEnv->e_flags |= EF_INQUEUE;
7338e3d4 541 eatheader(CurEnv);
dd1fe05b
EA
542
543 /* do the delivery */
e6f08ab1 544 if (!bitset(EF_FATALERRS, CurEnv->e_flags))
75f95954 545 sendall(CurEnv, SM_DELIVER);
dd1fe05b 546
dd1fe05b 547 /* finish up and exit */
81b7d258
EA
548 finis();
549 }
550
551 /*
552 ** Parent -- pick up results.
553 */
554
555 errno = 0;
7338e3d4 556 (void) waitfor(i);
81b7d258
EA
557}
558\f/*
559** READQF -- read queue file and set up environment.
560**
561** Parameters:
7338e3d4 562** e -- the envelope of the job to run.
64912e7e
EA
563** full -- if set, read in all information. Otherwise just
564** read in info needed for a queue print.
81b7d258
EA
565**
566** Returns:
567** none.
568**
569** Side Effects:
570** cf is read and created as the current job, as though
571** we had been invoked by argument.
572*/
573
11e3f8b5 574readqf(e, full)
7338e3d4 575 register ENVELOPE *e;
64912e7e 576 bool full;
81b7d258 577{
11e3f8b5
EA
578 char *qf;
579 register FILE *qfp;
6a86d693 580 char buf[MAXFIELD];
611b763d 581 extern char *fgetfolded();
abae7b2d 582 extern ADDRESS *sendto();
81b7d258 583
81b7d258
EA
584 /*
585 ** Read and process the file.
586 */
587
11e3f8b5
EA
588 qf = queuename(e, 'q');
589 qfp = fopen(qf, "r");
590 if (qfp == NULL)
591 {
592 syserr("readqf: no control file %s", qf);
593 return;
594 }
595 FileName = qf;
560a80d9 596 LineNumber = 0;
64912e7e 597 if (Verbose && full)
7338e3d4 598 printf("\nRunning %s\n", e->e_id);
560a80d9 599 while (fgetfolded(buf, sizeof buf, qfp) != NULL)
81b7d258 600 {
81b7d258
EA
601 switch (buf[0])
602 {
603 case 'R': /* specify recipient */
abae7b2d 604 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
605 break;
606
607 case 'H': /* header */
64912e7e
EA
608 if (full)
609 (void) chompheader(&buf[1], FALSE);
81b7d258
EA
610 break;
611
baa0c390
EA
612 case 'M': /* message */
613 e->e_message = newstr(&buf[1]);
614 break;
615
81b7d258 616 case 'S': /* sender */
aba51985 617 setsender(newstr(&buf[1]));
81b7d258
EA
618 break;
619
620 case 'D': /* data file name */
64912e7e
EA
621 if (!full)
622 break;
7338e3d4 623 e->e_df = newstr(&buf[1]);
912acb74
EA
624 e->e_dfp = fopen(e->e_df, "r");
625 if (e->e_dfp == NULL)
7338e3d4 626 syserr("readqf: cannot open %s", e->e_df);
81b7d258
EA
627 break;
628
96476cab 629 case 'T': /* init time */
7338e3d4 630 (void) sscanf(&buf[1], "%ld", &e->e_ctime);
81b7d258
EA
631 break;
632
aba51985 633 case 'P': /* message priority */
7338e3d4 634 (void) sscanf(&buf[1], "%ld", &e->e_msgpriority);
9ccf54c4
EA
635
636 /* make sure that big things get sent eventually */
7338e3d4 637 e->e_msgpriority -= WKTIMEFACT;
dd1fe05b
EA
638 break;
639
81b7d258 640 default:
7338e3d4 641 syserr("readqf(%s): bad line \"%s\"", e->e_id, buf);
81b7d258
EA
642 break;
643 }
644 }
7338e3d4
EA
645
646 FileName = NULL;
81b7d258
EA
647}
648\f/*
64912e7e
EA
649** PRINTQUEUE -- print out a representation of the mail queue
650**
651** Parameters:
652** none.
653**
654** Returns:
655** none.
656**
657** Side Effects:
658** Prints a listing of the mail queue on the standard output.
659*/
660
661printqueue()
662{
663 register WORK *w;
664 FILE *f;
0490b7d7 665 int nrequests;
64912e7e
EA
666 char buf[MAXLINE];
667
668 /*
669 ** Read and order the queue.
670 */
671
0490b7d7 672 nrequests = orderq();
64912e7e
EA
673
674 /*
675 ** Print the work list that we have read.
676 */
677
678 /* first see if there is anything */
0490b7d7 679 if (nrequests <= 0)
64912e7e 680 {
0490b7d7 681 printf("Mail queue is empty\n");
64912e7e
EA
682 return;
683 }
684
d7b5594c 685 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
0490b7d7
EA
686 if (nrequests > WLSIZE)
687 printf(", only %d printed", WLSIZE);
688 printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
689 for (w = WorkQ; w != NULL; w = w->w_next)
690 {
691 struct stat st;
0490b7d7
EA
692 auto time_t submittime = 0;
693 long dfsize = -1;
560a80d9 694 int fd;
baa0c390
EA
695 char lf[20];
696 char message[MAXLINE];
64912e7e 697
560a80d9
EA
698 f = fopen(w->w_name, "r");
699 if (f == NULL)
700 {
701 errno = 0;
702 continue;
703 }
64912e7e 704 printf("%7s", w->w_name + 2);
0490b7d7
EA
705 strcpy(lf, w->w_name);
706 lf[0] = 'l';
707 if (stat(lf, &st) >= 0)
708 printf("*");
709 else
710 printf(" ");
711 errno = 0;
560a80d9 712
baa0c390 713 message[0] = '\0';
64912e7e
EA
714 while (fgets(buf, sizeof buf, f) != NULL)
715 {
64912e7e
EA
716 fixcrlf(buf, TRUE);
717 switch (buf[0])
718 {
baa0c390
EA
719 case 'M': /* error message */
720 strcpy(message, &buf[1]);
721 break;
722
64912e7e 723 case 'S': /* sender name */
8dc6e1ad 724 printf("%8ld %.16s %.45s", dfsize,
0490b7d7 725 ctime(&submittime), &buf[1]);
1742e60b
EA
726 if (message[0] != '\0')
727 printf("\n\t\t\t\t (%.43s)", message);
64912e7e
EA
728 break;
729
730 case 'R': /* recipient name */
1742e60b 731 printf("\n\t\t\t\t %.45s", &buf[1]);
64912e7e
EA
732 break;
733
734 case 'T': /* creation time */
0490b7d7
EA
735 sscanf(&buf[1], "%ld", &submittime);
736 break;
737
738 case 'D': /* data file name */
739 if (stat(&buf[1], &st) >= 0)
740 dfsize = st.st_size;
64912e7e
EA
741 break;
742 }
743 }
0490b7d7
EA
744 if (submittime == (time_t) 0)
745 printf(" (no control file)");
64912e7e
EA
746 printf("\n");
747 fclose(f);
748 }
749}
884a20cb
EA
750
751# endif QUEUE
560a80d9
EA
752\f/*
753** QUEUENAME -- build a file name in the queue directory for this envelope.
754**
755** Assigns an id code if one does not already exist.
756** This code is very careful to avoid trashing existing files
757** under any circumstances.
758** We first create an nf file that is only used when
759** assigning an id. This file is always empty, so that
760** we can never accidently truncate an lf file.
761**
762** Parameters:
763** e -- envelope to build it in/from.
764** type -- the file type, used as the first character
765** of the file name.
766**
767** Returns:
768** a pointer to the new file name (in a static buffer).
769**
770** Side Effects:
771** Will create the lf and qf files if no id code is
772** already assigned. This will cause the envelope
773** to be modified.
774*/
775
776char *
777queuename(e, type)
778 register ENVELOPE *e;
779 char type;
780{
781 static char buf[MAXNAME];
782 static int pid = -1;
783 char c1 = 'A';
784 char c2 = 'A';
785
786 if (e->e_id == NULL)
787 {
788 char qf[20];
789 char nf[20];
560a80d9 790 char lf[20];
560a80d9
EA
791
792 /* find a unique id */
793 if (pid != getpid())
794 {
795 /* new process -- start back at "AA" */
796 pid = getpid();
797 c1 = 'A';
798 c2 = 'A' - 1;
799 }
800 (void) sprintf(qf, "qfAA%05d", pid);
560a80d9
EA
801 strcpy(lf, qf);
802 lf[0] = 'l';
560a80d9
EA
803 strcpy(nf, qf);
804 nf[0] = 'n';
805
806 while (c1 < '~' || c2 < 'Z')
807 {
808 int i;
809
810 if (c2 >= 'Z')
811 {
812 c1++;
813 c2 = 'A' - 1;
814 }
11e3f8b5
EA
815 lf[2] = nf[2] = qf[2] = c1;
816 lf[3] = nf[3] = qf[3] = ++c2;
560a80d9
EA
817# ifdef DEBUG
818 if (tTd(7, 20))
819 printf("queuename: trying \"%s\"\n", nf);
820# endif DEBUG
821
560a80d9
EA
822# ifdef QUEUE
823 if (access(lf, 0) >= 0 || access(qf, 0) >= 0)
824 continue;
825 errno = 0;
826 i = creat(nf, FileMode);
827 if (i < 0)
828 {
829 (void) unlink(nf); /* kernel bug */
830 continue;
831 }
832 (void) close(i);
833 i = link(nf, lf);
834 (void) unlink(nf);
835 if (i < 0)
836 continue;
837 if (link(lf, qf) >= 0)
838 break;
839 (void) unlink(lf);
840# else QUEUE
841 if (close(creat(qf, FileMode)) < 0)
842 continue;
843# endif QUEUE
560a80d9
EA
844 }
845 if (c1 >= '~' && c2 >= 'Z')
846 {
847 syserr("queuename: Cannot create \"%s\" in \"%s\"",
848 qf, QueueDir);
849 exit(EX_OSERR);
850 }
851 e->e_id = newstr(&qf[2]);
852 define('i', e->e_id, e);
853# ifdef DEBUG
854 if (tTd(7, 1))
855 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
856# ifdef LOG
857 if (LogLevel > 16)
858 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
859# endif LOG
860# endif DEBUG
861 }
862
863 if (type == '\0')
864 return (NULL);
865 (void) sprintf(buf, "%cf%s", type, e->e_id);
866# ifdef DEBUG
867 if (tTd(7, 2))
868 printf("queuename: %s\n", buf);
869# endif DEBUG
870 return (buf);
871}
872\f/*
873** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
874**
875** Parameters:
876** e -- the envelope to unlock.
877**
878** Returns:
879** none
880**
881** Side Effects:
882** unlocks the queue for `e'.
883*/
884
885unlockqueue(e)
886 ENVELOPE *e;
887{
888 /* remove the transcript */
889#ifdef DEBUG
890# ifdef LOG
891 if (LogLevel > 19)
892 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
893# endif LOG
894 if (!tTd(51, 4))
895#endif DEBUG
896 xunlink(queuename(e, 'x'));
897
898# ifdef QUEUE
560a80d9
EA
899 /* last but not least, remove the lock */
900 xunlink(queuename(e, 'l'));
560a80d9
EA
901# endif QUEUE
902}