Commit | Line | Data |
---|---|---|
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 |
bb09c502 | 8 | SCCSID(@(#)queue.c 4.5 %G% (no queueing)); |
884a20cb EA |
9 | # else QUEUE |
10 | ||
bb09c502 | 11 | SCCSID(@(#)queue.c 4.5 %G%); |
81b7d258 EA |
12 | |
13 | /* | |
7338e3d4 EA |
14 | ** Work queue. |
15 | */ | |
16 | ||
17 | struct 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 | ||
24 | typedef struct work WORK; | |
25 | ||
26 | WORK *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 | 43 | queueup(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 |
239 | runqueue(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 |
319 | static struct dir dbuf; |
320 | # define closedir(f) fclose(f) | |
321 | # endif DIR | |
322 | ||
81b7d258 EA |
323 | orderq() |
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 | 453 | workcmpf(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 | ||
477 | dowork(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 | 574 | readqf(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 | ||
661 | printqueue() | |
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 | ||
776 | char * | |
777 | queuename(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 | |
bb09c502 EA |
841 | if (close(creat(qf, FileMode)) >= 0) |
842 | break; | |
560a80d9 | 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 | ||
885 | unlockqueue(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 | } |