Commit | Line | Data |
---|---|---|
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 |
20 | static 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 |
25 | static char SccsId[] = "@(#)queue.c 5.4 (Berkeley) %G%"; | |
26 | # endif not lint | |
81b7d258 EA |
27 | |
28 | /* | |
7338e3d4 EA |
29 | ** Work queue. |
30 | */ | |
31 | ||
32 | struct 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 | ||
39 | typedef struct work WORK; | |
40 | ||
41 | WORK *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 | 58 | queueup(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 |
254 | runqueue(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 |
334 | static struct dir dbuf; |
335 | # define closedir(f) fclose(f) | |
336 | # endif DIR | |
337 | ||
81b7d258 EA |
338 | orderq() |
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 | 468 | workcmpf(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 | ||
492 | dowork(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 | 589 | readqf(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 | ||
676 | printqueue() | |
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 | ||
790 | char * | |
791 | queuename(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 | ||
899 | unlockqueue(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 | } |