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