Commit | Line | Data |
---|---|---|
81b7d258 EA |
1 | # include "sendmail.h" |
2 | # include <sys/stat.h> | |
ccd1d833 | 3 | # include <ndir.h> |
aba51985 | 4 | # include <signal.h> |
81b7d258 EA |
5 | # include <errno.h> |
6 | ||
884a20cb | 7 | # ifndef QUEUE |
1ff06f70 | 8 | SCCSID(@(#)queue.c 3.14 %G% (no queueing)); |
884a20cb EA |
9 | # else QUEUE |
10 | ||
1ff06f70 | 11 | SCCSID(@(#)queue.c 3.14 %G%); |
81b7d258 EA |
12 | |
13 | /* | |
14 | ** QUEUEUP -- queue a message up for future transmission. | |
15 | ** | |
16 | ** The queued message should already be in the correct place. | |
17 | ** This routine just outputs the control file as appropriate. | |
18 | ** | |
19 | ** Parameters: | |
dd1fe05b | 20 | ** e -- the envelope to queue up. |
81b7d258 EA |
21 | ** |
22 | ** Returns: | |
23 | ** none. | |
24 | ** | |
25 | ** Side Effects: | |
26 | ** The current request (only unsatisfied addresses) | |
27 | ** are saved in a control file. | |
28 | */ | |
29 | ||
dd1fe05b EA |
30 | queueup(e) |
31 | register ENVELOPE *e; | |
81b7d258 EA |
32 | { |
33 | char cf[MAXNAME]; | |
dd1fe05b EA |
34 | char buf[MAXNAME]; |
35 | register FILE *cfp; | |
81b7d258 | 36 | register HDR *h; |
d4f42161 | 37 | register ADDRESS *q; |
4e5e456f | 38 | extern char *mktemp(); |
808ac89b | 39 | register int i; |
81b7d258 | 40 | |
9ccf54c4 EA |
41 | /* |
42 | ** Create control file. | |
43 | */ | |
81b7d258 | 44 | |
9ccf54c4 | 45 | strcpy(cf, QueueDir); |
dd1fe05b | 46 | strcat(cf, "/tfXXXXXX"); |
9ccf54c4 | 47 | (void) mktemp(cf); |
dd1fe05b EA |
48 | cfp = fopen(cf, "w"); |
49 | if (cfp == NULL) | |
81b7d258 EA |
50 | { |
51 | syserr("queueup: cannot create control file %s", cf); | |
52 | return; | |
53 | } | |
54 | ||
55 | # ifdef DEBUG | |
56 | if (Debug) | |
dd1fe05b | 57 | printf("queueing in %s\n", cf); |
81b7d258 EA |
58 | # endif DEBUG |
59 | ||
dd1fe05b EA |
60 | /* |
61 | ** If there is no data file yet, create one. | |
62 | */ | |
63 | ||
64 | if (e->e_df == NULL) | |
65 | { | |
66 | register FILE *dfp; | |
67 | ||
68 | strcpy(buf, QueueDir); | |
69 | strcat(buf, "/dfXXXXXX"); | |
70 | e->e_df = newstr(mktemp(buf)); | |
71 | dfp = fopen(e->e_df, "w"); | |
72 | if (dfp == NULL) | |
73 | { | |
74 | syserr("queueup: cannot create %s", e->e_df); | |
75 | fclose(cfp); | |
76 | return; | |
77 | } | |
78 | (*e->e_putbody)(dfp, Mailer[1], FALSE); | |
79 | fclose(dfp); | |
80 | } | |
81 | ||
81b7d258 EA |
82 | /* |
83 | ** Output future work requests. | |
84 | */ | |
85 | ||
86 | /* output name of data file */ | |
dd1fe05b | 87 | fprintf(cfp, "D%s\n", e->e_df); |
81b7d258 EA |
88 | |
89 | /* output name of sender */ | |
dd1fe05b | 90 | fprintf(cfp, "S%s\n", e->e_from.q_paddr); |
81b7d258 EA |
91 | |
92 | /* output timeout */ | |
dd1fe05b | 93 | fprintf(cfp, "T%ld\n", TimeOut); |
81b7d258 | 94 | |
aba51985 | 95 | /* output message priority */ |
dd1fe05b EA |
96 | fprintf(cfp, "P%ld\n", e->e_msgpriority); |
97 | ||
98 | /* output message class */ | |
99 | fprintf(cfp, "C%d\n", e->e_class); | |
aba51985 | 100 | |
808ac89b EA |
101 | /* output macro definitions */ |
102 | for (i = 0; i < 128; i++) | |
103 | { | |
dd1fe05b | 104 | register char *p = e->e_macro[i]; |
808ac89b EA |
105 | |
106 | if (p != NULL && i != (int) 'b') | |
dd1fe05b | 107 | fprintf(cfp, "M%c%s\n", i, p); |
808ac89b EA |
108 | } |
109 | ||
81b7d258 | 110 | /* output list of recipient addresses */ |
dd1fe05b | 111 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
81b7d258 | 112 | { |
9ccf54c4 EA |
113 | # ifdef DEBUG |
114 | if (Debug > 0) | |
115 | { | |
116 | printf("queueing "); | |
117 | printaddr(q, FALSE); | |
118 | } | |
119 | # endif DEBUG | |
120 | if (bitset(QQUEUEUP, q->q_flags)) | |
dd1fe05b | 121 | fprintf(cfp, "R%s\n", q->q_paddr); |
81b7d258 EA |
122 | } |
123 | ||
124 | /* output headers for this message */ | |
dd1fe05b | 125 | for (h = e->e_header; h != NULL; h = h->h_link) |
81b7d258 EA |
126 | { |
127 | if (h->h_value == NULL || h->h_value[0] == '\0') | |
128 | continue; | |
dd1fe05b | 129 | fprintf(cfp, "H"); |
81b7d258 | 130 | if (h->h_mflags != 0 && bitset(H_CHECK|H_ACHECK, h->h_flags)) |
dd1fe05b EA |
131 | mfdecode(h->h_mflags, cfp); |
132 | fprintf(cfp, "%s: %s\n", h->h_field, h->h_value); | |
81b7d258 EA |
133 | } |
134 | ||
135 | /* | |
136 | ** Clean up. | |
137 | */ | |
138 | ||
dd1fe05b EA |
139 | (void) fclose(cfp); |
140 | (void) strcpy(buf, QueueDir); | |
141 | (void) strcat(buf, "/cfXXXXXX"); | |
142 | (void) mktemp(buf); | |
143 | if (link(cf, buf) < 0) | |
144 | syserr("cannot link(%s, %s), df=%s", cf, buf, e->e_df); | |
145 | else | |
146 | unlink(cf); | |
81b7d258 EA |
147 | } |
148 | \f/* | |
149 | ** RUNQUEUE -- run the jobs in the queue. | |
150 | ** | |
151 | ** Gets the stuff out of the queue in some presumably logical | |
152 | ** order and processes them. | |
153 | ** | |
154 | ** Parameters: | |
155 | ** none. | |
156 | ** | |
157 | ** Returns: | |
158 | ** none. | |
159 | ** | |
160 | ** Side Effects: | |
161 | ** runs things in the mail queue. | |
162 | */ | |
163 | ||
2cf55cb7 EA |
164 | bool ReorderQueue; /* if set, reorder the send queue */ |
165 | int QueuePid; /* pid of child running queue */ | |
aba51985 | 166 | |
2cf55cb7 EA |
167 | runqueue(forkflag) |
168 | bool forkflag; | |
81b7d258 | 169 | { |
aba51985 | 170 | extern reordersig(); |
81b7d258 | 171 | |
2cf55cb7 EA |
172 | if (QueueIntvl != 0) |
173 | { | |
62fff4f9 EA |
174 | (void) signal(SIGALRM, reordersig); |
175 | (void) alarm((unsigned) QueueIntvl); | |
2cf55cb7 EA |
176 | } |
177 | ||
178 | if (forkflag) | |
179 | { | |
180 | QueuePid = dofork(); | |
181 | if (QueuePid > 0) | |
182 | { | |
183 | /* parent */ | |
184 | return; | |
185 | } | |
186 | else | |
62fff4f9 | 187 | (void) alarm((unsigned) 0); |
2cf55cb7 EA |
188 | } |
189 | ||
aba51985 EA |
190 | for (;;) |
191 | { | |
192 | /* | |
193 | ** Order the existing work requests. | |
194 | */ | |
81b7d258 | 195 | |
aba51985 | 196 | orderq(); |
81b7d258 | 197 | |
aba51985 EA |
198 | if (WorkQ == NULL) |
199 | { | |
200 | /* no work? well, maybe later */ | |
201 | if (QueueIntvl == 0) | |
202 | break; | |
2cf55cb7 | 203 | pause(); |
aba51985 EA |
204 | continue; |
205 | } | |
81b7d258 | 206 | |
aba51985 | 207 | ReorderQueue = FALSE; |
aba51985 EA |
208 | |
209 | /* | |
210 | ** Process them once at a time. | |
211 | ** The queue could be reordered while we do this to take | |
212 | ** new requests into account. If so, the existing job | |
213 | ** will be finished but the next thing taken off WorkQ | |
214 | ** may be something else. | |
215 | */ | |
216 | ||
217 | while (WorkQ != NULL) | |
218 | { | |
219 | WORK *w = WorkQ; | |
220 | ||
221 | WorkQ = WorkQ->w_next; | |
222 | dowork(w); | |
223 | free(w->w_name); | |
224 | free((char *) w); | |
225 | if (ReorderQueue) | |
226 | break; | |
227 | } | |
228 | ||
229 | if (QueueIntvl == 0) | |
230 | break; | |
81b7d258 | 231 | } |
14a39063 EA |
232 | |
233 | /* no work to do -- just exit */ | |
234 | finis(); | |
81b7d258 EA |
235 | } |
236 | \f/* | |
aba51985 EA |
237 | ** REORDERSIG -- catch the alarm signal and tell sendmail to reorder queue. |
238 | ** | |
239 | ** Parameters: | |
240 | ** none. | |
241 | ** | |
242 | ** Returns: | |
243 | ** none. | |
244 | ** | |
245 | ** Side Effects: | |
246 | ** sets the "reorder work queue" flag. | |
247 | */ | |
248 | ||
249 | reordersig() | |
250 | { | |
2cf55cb7 EA |
251 | if (QueuePid == 0) |
252 | { | |
253 | /* we are in a child doing queueing */ | |
254 | ReorderQueue = TRUE; | |
255 | } | |
256 | else | |
257 | { | |
258 | /* we are in a parent -- poke child or start new one */ | |
259 | if (kill(QueuePid, SIGALRM) < 0) | |
260 | { | |
261 | /* no child -- get zombie & start new one */ | |
262 | static int st; | |
263 | ||
62fff4f9 | 264 | (void) wait(&st); |
2cf55cb7 EA |
265 | QueuePid = dofork(); |
266 | if (QueuePid == 0) | |
267 | { | |
268 | /* new child; run queue */ | |
62fff4f9 | 269 | runqueue(FALSE); |
2cf55cb7 EA |
270 | finis(); |
271 | } | |
272 | } | |
273 | } | |
274 | ||
275 | /* | |
276 | ** Arrange to get this signal again. | |
277 | */ | |
278 | ||
25b9d645 | 279 | (void) signal(SIGALRM, reordersig); |
62fff4f9 | 280 | (void) alarm((unsigned) QueueIntvl); |
aba51985 EA |
281 | } |
282 | \f/* | |
81b7d258 EA |
283 | ** ORDERQ -- order the work queue. |
284 | ** | |
285 | ** Parameters: | |
286 | ** none. | |
287 | ** | |
288 | ** Returns: | |
289 | ** none. | |
290 | ** | |
291 | ** Side Effects: | |
292 | ** Sets WorkQ to the queue of available work, in order. | |
293 | */ | |
294 | ||
295 | # define WLSIZE 120 /* max size of worklist per sort */ | |
296 | ||
297 | orderq() | |
298 | { | |
ccd1d833 | 299 | register struct direct *d; |
81b7d258 EA |
300 | register WORK *w; |
301 | register WORK **wp; /* parent of w */ | |
ccd1d833 | 302 | DIR *f; |
81b7d258 | 303 | register int i; |
81b7d258 EA |
304 | WORK wlist[WLSIZE]; |
305 | int wn = 0; | |
306 | extern workcmpf(); | |
307 | extern char *QueueDir; | |
308 | ||
309 | /* clear out old WorkQ */ | |
310 | for (w = WorkQ; w != NULL; ) | |
311 | { | |
312 | register WORK *nw = w->w_next; | |
313 | ||
314 | WorkQ = nw; | |
315 | free(w->w_name); | |
316 | free((char *) w); | |
317 | w = nw; | |
318 | } | |
319 | ||
320 | /* open the queue directory */ | |
ccd1d833 | 321 | f = opendir(QueueDir); |
81b7d258 EA |
322 | if (f == NULL) |
323 | { | |
324 | syserr("orderq: cannot open %s", QueueDir); | |
325 | return; | |
326 | } | |
327 | ||
328 | /* | |
329 | ** Read the work directory. | |
330 | */ | |
331 | ||
ccd1d833 | 332 | while (wn < WLSIZE && (d = readdir(f)) != NULL) |
81b7d258 EA |
333 | { |
334 | char cbuf[MAXNAME]; | |
335 | char lbuf[MAXNAME]; | |
336 | FILE *cf; | |
337 | register char *p; | |
338 | ||
339 | /* is this an interesting entry? */ | |
ccd1d833 | 340 | if (d->d_name[0] != 'c') |
81b7d258 EA |
341 | continue; |
342 | ||
343 | /* yes -- find the control file location */ | |
344 | strcpy(cbuf, QueueDir); | |
345 | strcat(cbuf, "/"); | |
346 | p = &cbuf[strlen(cbuf)]; | |
ccd1d833 | 347 | strcpy(p, d->d_name); |
81b7d258 EA |
348 | |
349 | /* open control file */ | |
350 | cf = fopen(cbuf, "r"); | |
351 | if (cf == NULL) | |
352 | { | |
353 | syserr("orderq: cannot open %s", cbuf); | |
354 | continue; | |
355 | } | |
9ccf54c4 | 356 | wlist[wn].w_name = newstr(cbuf); |
81b7d258 EA |
357 | |
358 | /* extract useful information */ | |
81b7d258 EA |
359 | while (fgets(lbuf, sizeof lbuf, cf) != NULL) |
360 | { | |
361 | fixcrlf(lbuf, TRUE); | |
362 | ||
363 | switch (lbuf[0]) | |
364 | { | |
81b7d258 | 365 | case 'P': /* message priority */ |
9ccf54c4 | 366 | (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); |
81b7d258 EA |
367 | break; |
368 | } | |
369 | } | |
370 | wn++; | |
371 | (void) fclose(cf); | |
372 | } | |
ccd1d833 | 373 | (void) closedir(f); |
81b7d258 EA |
374 | |
375 | /* | |
376 | ** Sort the work directory. | |
377 | */ | |
378 | ||
379 | qsort(wlist, wn, sizeof *wlist, workcmpf); | |
380 | ||
381 | /* | |
382 | ** Convert the work list into canonical form. | |
383 | */ | |
384 | ||
385 | wp = &WorkQ; | |
386 | for (i = 0; i < wn; i++) | |
387 | { | |
388 | w = (WORK *) xalloc(sizeof *w); | |
389 | w->w_name = wlist[i].w_name; | |
81b7d258 EA |
390 | w->w_pri = wlist[i].w_pri; |
391 | w->w_next = NULL; | |
392 | *wp = w; | |
393 | wp = &w->w_next; | |
394 | } | |
395 | ||
396 | # ifdef DEBUG | |
397 | if (Debug) | |
398 | { | |
399 | for (w = WorkQ; w != NULL; w = w->w_next) | |
9ccf54c4 | 400 | printf("%32s: pri=%ld\n", w->w_name, w->w_pri); |
81b7d258 EA |
401 | } |
402 | # endif DEBUG | |
403 | } | |
404 | \f/* | |
405 | ** WORKCMPF -- compare function for ordering work. | |
406 | ** | |
407 | ** Parameters: | |
408 | ** a -- the first argument. | |
409 | ** b -- the second argument. | |
410 | ** | |
411 | ** Returns: | |
412 | ** -1 if a < b | |
413 | ** 0 if a == b | |
414 | ** 1 if a > b | |
415 | ** | |
416 | ** Side Effects: | |
417 | ** none. | |
418 | */ | |
419 | ||
420 | # define PRIFACT 1800 /* bytes each priority point is worth */ | |
421 | ||
422 | workcmpf(a, b) | |
9ccf54c4 EA |
423 | register WORK *a; |
424 | register WORK *b; | |
81b7d258 | 425 | { |
9ccf54c4 | 426 | if (a->w_pri == b->w_pri) |
81b7d258 | 427 | return (0); |
9ccf54c4 | 428 | else if (a->w_pri > b->w_pri) |
81b7d258 EA |
429 | return (1); |
430 | else | |
431 | return (-1); | |
432 | } | |
433 | \f/* | |
434 | ** DOWORK -- do a work request. | |
435 | ** | |
436 | ** Parameters: | |
437 | ** w -- the work request to be satisfied. | |
438 | ** | |
439 | ** Returns: | |
440 | ** none. | |
441 | ** | |
442 | ** Side Effects: | |
443 | ** The work request is satisfied if possible. | |
444 | */ | |
445 | ||
446 | dowork(w) | |
447 | register WORK *w; | |
448 | { | |
449 | register int i; | |
450 | auto int xstat; | |
451 | ||
452 | # ifdef DEBUG | |
453 | if (Debug) | |
9ccf54c4 | 454 | printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); |
81b7d258 EA |
455 | # endif DEBUG |
456 | ||
457 | /* | |
458 | ** Fork for work. | |
459 | */ | |
460 | ||
461 | i = fork(); | |
462 | if (i < 0) | |
463 | { | |
464 | syserr("dowork: cannot fork"); | |
465 | return; | |
466 | } | |
467 | ||
468 | if (i == 0) | |
469 | { | |
dd1fe05b EA |
470 | char buf[MAXNAME]; |
471 | ||
81b7d258 EA |
472 | /* |
473 | ** CHILD | |
dd1fe05b EA |
474 | ** Change the name of the control file to avoid |
475 | ** duplicate deliveries. Then run the file as | |
476 | ** though we had just read it. | |
81b7d258 EA |
477 | */ |
478 | ||
479 | QueueRun = TRUE; | |
1ff06f70 | 480 | MailBack = TRUE; |
dd1fe05b EA |
481 | (void) strcpy(buf, QueueDir); |
482 | (void) strcat(buf, "/tfXXXXXX"); | |
483 | (void) mktemp(buf); | |
484 | if (link(w->w_name, buf) < 0) | |
485 | { | |
486 | syserr("dowork: link(%s, %s)", w->w_name, buf); | |
487 | ||
488 | /* it's ok to lie -- it will be run later */ | |
489 | exit(EX_OK); | |
490 | } | |
491 | (void) unlink(w->w_name); | |
492 | ||
493 | /* create ourselves a transcript file */ | |
aba51985 | 494 | openxscrpt(); |
dd1fe05b EA |
495 | |
496 | /* do basic system initialization */ | |
81b7d258 | 497 | initsys(); |
dd1fe05b EA |
498 | |
499 | /* read the queue control file */ | |
500 | readqf(buf); | |
501 | ||
502 | /* do the delivery */ | |
81b7d258 | 503 | sendall(FALSE); |
dd1fe05b EA |
504 | |
505 | /* if still not sent, perhaps we should time out.... */ | |
aba51985 EA |
506 | # ifdef DEBUG |
507 | if (Debug > 2) | |
508 | printf("CurTime=%ld, TimeOut=%ld\n", CurTime, TimeOut); | |
509 | # endif DEBUG | |
2654b031 | 510 | if (CurEnv->e_queueup && CurTime > TimeOut) |
aba51985 | 511 | timeout(w); |
dd1fe05b EA |
512 | |
513 | /* get rid of the temporary file -- a new cf will be made */ | |
514 | (void) unlink(buf); | |
515 | ||
516 | /* finish up and exit */ | |
81b7d258 EA |
517 | finis(); |
518 | } | |
519 | ||
520 | /* | |
521 | ** Parent -- pick up results. | |
522 | */ | |
523 | ||
524 | errno = 0; | |
525 | while ((i = wait(&xstat)) > 0 && errno != EINTR) | |
526 | { | |
527 | if (errno == EINTR) | |
528 | { | |
529 | errno = 0; | |
530 | } | |
531 | } | |
532 | } | |
533 | \f/* | |
534 | ** READQF -- read queue file and set up environment. | |
535 | ** | |
536 | ** Parameters: | |
537 | ** cf -- name of queue control file. | |
538 | ** | |
539 | ** Returns: | |
540 | ** none. | |
541 | ** | |
542 | ** Side Effects: | |
543 | ** cf is read and created as the current job, as though | |
544 | ** we had been invoked by argument. | |
545 | */ | |
546 | ||
547 | readqf(cf) | |
548 | char *cf; | |
549 | { | |
550 | register FILE *f; | |
551 | char buf[MAXLINE]; | |
abae7b2d | 552 | extern ADDRESS *sendto(); |
81b7d258 EA |
553 | |
554 | /* | |
555 | ** Open the file created by queueup. | |
556 | */ | |
557 | ||
558 | f = fopen(cf, "r"); | |
559 | if (f == NULL) | |
560 | { | |
561 | syserr("readqf: no cf file %s", cf); | |
562 | return; | |
563 | } | |
564 | ||
565 | /* | |
566 | ** Read and process the file. | |
567 | */ | |
568 | ||
9ccf54c4 | 569 | if (Verbose) |
2654b031 | 570 | message(Arpa_Info, "Running %s", cf); |
9ccf54c4 | 571 | |
81b7d258 EA |
572 | while (fgets(buf, sizeof buf, f) != NULL) |
573 | { | |
574 | fixcrlf(buf, TRUE); | |
575 | ||
576 | switch (buf[0]) | |
577 | { | |
578 | case 'R': /* specify recipient */ | |
abae7b2d | 579 | (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0); |
81b7d258 EA |
580 | break; |
581 | ||
582 | case 'H': /* header */ | |
583 | (void) chompheader(&buf[1], FALSE); | |
584 | break; | |
585 | ||
586 | case 'S': /* sender */ | |
aba51985 | 587 | setsender(newstr(&buf[1])); |
81b7d258 EA |
588 | break; |
589 | ||
590 | case 'D': /* data file name */ | |
1ff06f70 EA |
591 | CurEnv->e_df = newstr(&buf[1]); |
592 | TempFile = fopen(CurEnv->e_df, "r"); | |
81b7d258 | 593 | if (TempFile == NULL) |
1ff06f70 | 594 | syserr("readqf: cannot open %s", CurEnv->e_df); |
81b7d258 EA |
595 | break; |
596 | ||
597 | case 'T': /* timeout */ | |
598 | (void) sscanf(&buf[1], "%ld", &TimeOut); | |
599 | break; | |
600 | ||
aba51985 | 601 | case 'P': /* message priority */ |
2654b031 | 602 | (void) sscanf(&buf[1], "%ld", &CurEnv->e_msgpriority); |
9ccf54c4 EA |
603 | |
604 | /* make sure that big things get sent eventually */ | |
2654b031 | 605 | CurEnv->e_msgpriority -= WKTIMEFACT; |
aba51985 EA |
606 | break; |
607 | ||
dd1fe05b EA |
608 | case 'C': /* message class */ |
609 | (void) sscanf(&buf[1], "%hd", &CurEnv->e_class); | |
610 | break; | |
611 | ||
808ac89b EA |
612 | case 'M': /* define macro */ |
613 | define(buf[1], newstr(&buf[2])); | |
614 | break; | |
615 | ||
81b7d258 EA |
616 | default: |
617 | syserr("readqf(%s): bad line \"%s\"", cf, buf); | |
618 | break; | |
619 | } | |
620 | } | |
621 | } | |
622 | \f/* | |
623 | ** TIMEOUT -- process timeout on queue file. | |
624 | ** | |
625 | ** Parameters: | |
626 | ** w -- pointer to work request that timed out. | |
627 | ** | |
628 | ** Returns: | |
629 | ** none. | |
630 | ** | |
631 | ** Side Effects: | |
632 | ** Returns a message to the sender saying that this | |
633 | ** message has timed out. | |
634 | */ | |
635 | ||
636 | timeout(w) | |
637 | register WORK *w; | |
638 | { | |
aba51985 EA |
639 | # ifdef DEBUG |
640 | if (Debug > 0) | |
641 | printf("timeout(%s)\n", w->w_name); | |
642 | # endif DEBUG | |
1ff06f70 | 643 | message(Arpa_Info, "Message has timed out"); |
aba51985 EA |
644 | |
645 | /* return message to sender */ | |
dd1fe05b EA |
646 | (void) returntosender("Cannot send mail for three days", |
647 | &CurEnv->e_from, TRUE); | |
aba51985 EA |
648 | |
649 | /* arrange to remove files from queue */ | |
2654b031 | 650 | CurEnv->e_queueup = FALSE; |
81b7d258 | 651 | } |
884a20cb EA |
652 | |
653 | # endif QUEUE |