Debug: option access for expansion
[exim.git] / src / src / transports / autoreply.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
9
10
11 #include "../exim.h"
12 #include "autoreply.h"
13
14
15
16 /* Options specific to the autoreply transport. They must be in alphabetic
17 order (note that "_" comes before the lower case letters). Those starting
18 with "*" are not settable by the user but are used by the option-reading
19 software for alternative value types. Some options are publicly visible and so
20 are stored in the driver instance block. These are flagged with opt_public. */
21 #define LOFF(field) OPT_OFF(autoreply_transport_options_block, field)
22
23 optionlist autoreply_transport_options[] = {
24   { "bcc",               opt_stringptr, LOFF(bcc) },
25   { "cc",                opt_stringptr, LOFF(cc) },
26   { "file",              opt_stringptr, LOFF(file) },
27   { "file_expand",     opt_bool,        LOFF(file_expand) },
28   { "file_optional",     opt_bool,      LOFF(file_optional) },
29   { "from",              opt_stringptr, LOFF(from) },
30   { "headers",           opt_stringptr, LOFF(headers) },
31   { "log",               opt_stringptr, LOFF(logfile) },
32   { "mode",              opt_octint,    LOFF(mode) },
33   { "never_mail",        opt_stringptr, LOFF(never_mail) },
34   { "once",              opt_stringptr, LOFF(oncelog) },
35   { "once_file_size",    opt_int,       LOFF(once_file_size) },
36   { "once_repeat",       opt_stringptr, LOFF(once_repeat) },
37   { "reply_to",          opt_stringptr, LOFF(reply_to) },
38   { "return_message",    opt_bool,      LOFF(return_message) },
39   { "subject",           opt_stringptr, LOFF(subject) },
40   { "text",              opt_stringptr, LOFF(text) },
41   { "to",                opt_stringptr, LOFF(to) },
42 };
43
44 /* Size of the options list. An extern variable has to be used so that its
45 address can appear in the tables drtables.c. */
46
47 int autoreply_transport_options_count =
48   sizeof(autoreply_transport_options)/sizeof(optionlist);
49
50
51 #ifdef MACRO_PREDEF
52
53 /* Dummy values */
54 autoreply_transport_options_block autoreply_transport_option_defaults = {0};
55 void autoreply_transport_init(transport_instance *tblock) {}
56 BOOL autoreply_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
57
58 #else   /*!MACRO_PREDEF*/
59
60
61 /* Default private options block for the autoreply transport.
62 All non-mentioned lements zero/null/false. */
63
64 autoreply_transport_options_block autoreply_transport_option_defaults = {
65   .mode = 0600,
66 };
67
68
69
70 /* Type of text for the checkexpand() function */
71
72 enum { cke_text, cke_hdr, cke_file };
73
74
75
76 /*************************************************
77 *          Initialization entry point            *
78 *************************************************/
79
80 /* Called for each instance, after its options have been read, to
81 enable consistency checks to be done, or anything else that needs
82 to be set up. */
83
84 void
85 autoreply_transport_init(transport_instance *tblock)
86 {
87 /*
88 autoreply_transport_options_block *ob =
89   (autoreply_transport_options_block *)(tblock->options_block);
90 */
91
92 /* If a fixed uid field is set, then a gid field must also be set. */
93
94 if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL)
95   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
96     "user set without group for the %s transport", tblock->name);
97 }
98
99
100
101
102 /*************************************************
103 *          Expand string and check               *
104 *************************************************/
105
106 /* If the expansion fails, the error is set up in the address. Expanded
107 strings must be checked to ensure they contain only printing characters
108 and white space. If not, the function fails.
109
110 Arguments:
111    s         string to expand
112    addr      address that is being worked on
113    name      transport name, for error text
114    type      type, for checking content:
115                cke_text => no check
116                cke_hdr  => header, allow \n + whitespace
117                cke_file => file name, no non-printers allowed
118
119 Returns:     expanded string if expansion succeeds;
120              NULL otherwise
121 */
122
123 static uschar *
124 checkexpand(uschar *s, address_item *addr, uschar *name, int type)
125 {
126 uschar *ss = expand_string(s);
127
128 if (!ss)
129   {
130   addr->transport_return = FAIL;
131   addr->message = string_sprintf("Expansion of \"%s\" failed in %s transport: "
132     "%s", s, name, expand_string_message);
133   return NULL;
134   }
135
136 if (type != cke_text) for (uschar * t = ss; *t != 0; t++)
137   {
138   int c = *t;
139   const uschar * sp;
140   if (mac_isprint(c)) continue;
141   if (type == cke_hdr && c == '\n' && (t[1] == ' ' || t[1] == '\t')) continue;
142   sp = string_printing(s);
143   addr->transport_return = FAIL;
144   addr->message = string_sprintf("Expansion of \"%s\" in %s transport "
145     "contains non-printing character %d", sp, name, c);
146   return NULL;
147   }
148
149 return ss;
150 }
151
152
153
154
155 /*************************************************
156 *          Check a header line for never_mail    *
157 *************************************************/
158
159 /* This is called to check to, cc, and bcc for addresses in the never_mail
160 list. Any that are found are removed.
161
162 Arguments:
163   list        list of addresses to be checked
164   never_mail  an address list, already expanded
165
166 Returns:      edited replacement address list, or NULL, or original
167 */
168
169 static uschar *
170 check_never_mail(uschar * list, const uschar * never_mail)
171 {
172 rmark reset_point = store_mark();
173 uschar * newlist = string_copy(list);
174 uschar * s = newlist;
175 BOOL hit = FALSE;
176
177 while (*s)
178   {
179   uschar *error, *next;
180   uschar *e = parse_find_address_end(s, FALSE);
181   int terminator = *e;
182   int start, end, domain, rc;
183
184   /* Temporarily terminate the string at the address end while extracting
185   the operative address within. */
186
187   *e = 0;
188   next = parse_extract_address(s, &error, &start, &end, &domain, FALSE);
189   *e = terminator;
190
191   /* If there is some kind of syntax error, just give up on this header
192   line. */
193
194   if (!next) break;
195
196   /* See if the address is on the never_mail list */
197
198   rc = match_address_list(next,         /* address to check */
199                           TRUE,         /* start caseless */
200                           FALSE,        /* don't expand the list */
201                           &never_mail,  /* the list */
202                           NULL,         /* no caching */
203                           -1,           /* no expand setup */
204                           0,            /* separator from list */
205                           NULL);        /* no lookup value return */
206
207   if (rc == OK)                         /* Remove this address */
208     {
209     DEBUG(D_transport)
210       debug_printf("discarding recipient %s (matched never_mail)\n", next);
211     hit = TRUE;
212     if (terminator == ',') e++;
213     memmove(s, e, Ustrlen(e) + 1);
214     }
215   else                                  /* Skip over this address */
216     {
217     s = e;
218     if (terminator == ',') s++;
219     }
220   }
221
222 /* If no addresses were removed, retrieve the memory used and return
223 the original. */
224
225 if (!hit)
226   {
227   store_reset(reset_point);
228   return list;
229   }
230
231 /* Check to see if we removed the last address, leaving a terminating comma
232 that needs to be removed */
233
234 s = newlist + Ustrlen(newlist);
235 while (s > newlist && (isspace(s[-1]) || s[-1] == ',')) s--;
236 *s = 0;
237
238 /* Check to see if there any addresses left; if not, return NULL */
239
240 s = newlist;
241 while (s && isspace(*s)) s++;
242 if (*s)
243   return newlist;
244
245 store_reset(reset_point);
246 return NULL;
247 }
248
249
250
251 /*************************************************
252 *              Main entry point                  *
253 *************************************************/
254
255 /* See local README for interface details. This transport always returns
256 FALSE, indicating that the top address has the status for all - though in fact
257 this transport can handle only one address at at time anyway. */
258
259 BOOL
260 autoreply_transport_entry(
261   transport_instance *tblock,      /* data for this instantiation */
262   address_item *addr)              /* address we are working on */
263 {
264 int fd, pid, rc;
265 int cache_fd = -1;
266 int cache_size = 0;
267 int add_size = 0;
268 EXIM_DB * dbm_file = NULL;
269 BOOL file_expand, return_message;
270 uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
271 uschar *logfile, *oncelog;
272 uschar *cache_buff = NULL;
273 uschar *cache_time = NULL;
274 uschar *message_id = NULL;
275 header_line *h;
276 time_t now = time(NULL);
277 time_t once_repeat_sec = 0;
278 FILE *fp;
279 FILE *ff = NULL;
280
281 autoreply_transport_options_block *ob =
282   (autoreply_transport_options_block *)(tblock->options_block);
283
284 DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name);
285
286 /* Set up for the good case */
287
288 addr->transport_return = OK;
289 addr->basic_errno = 0;
290
291 /* If the address is pointing to a reply block, then take all the data
292 from that block. It has typically been set up by a mail filter processing
293 router. Otherwise, the data must be supplied by this transport, and
294 it has to be expanded here. */
295
296 if (addr->reply)
297   {
298   DEBUG(D_transport) debug_printf("taking data from address\n");
299   from = addr->reply->from;
300   reply_to = addr->reply->reply_to;
301   to = addr->reply->to;
302   cc = addr->reply->cc;
303   bcc = addr->reply->bcc;
304   subject = addr->reply->subject;
305   headers = addr->reply->headers;
306   text = addr->reply->text;
307   file = addr->reply->file;
308   logfile = addr->reply->logfile;
309   oncelog = addr->reply->oncelog;
310   once_repeat_sec = addr->reply->once_repeat;
311   file_expand = addr->reply->file_expand;
312   expand_forbid = addr->reply->expand_forbid;
313   return_message = addr->reply->return_message;
314   }
315 else
316   {
317   uschar * oncerepeat;
318
319   DEBUG(D_transport) debug_printf("taking data from transport\n");
320   GET_OPTION("once_repeat");    oncerepeat = ob->once_repeat;
321   GET_OPTION("from");           from = ob->from;
322   GET_OPTION("reply_to");       reply_to = ob->reply_to;
323   GET_OPTION("to");             to = ob->to;
324   GET_OPTION("cc");             cc = ob->cc;
325   GET_OPTION("bcc");            bcc = ob->bcc;
326   GET_OPTION("subject");        subject = ob->subject;
327   GET_OPTION("headers");        headers = ob->headers;
328   GET_OPTION("text");           text = ob->text;
329   GET_OPTION("file");           file = ob->file;
330   GET_OPTION("log");            logfile = ob->logfile;
331   GET_OPTION("once");           oncelog = ob->oncelog;
332   file_expand = ob->file_expand;
333   return_message = ob->return_message;
334
335   if (  from && !(from = checkexpand(from, addr, tblock->name, cke_hdr))
336      || reply_to && !(reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr))
337      || to && !(to = checkexpand(to, addr, tblock->name, cke_hdr))
338      || cc && !(cc = checkexpand(cc, addr, tblock->name, cke_hdr))
339      || bcc && !(bcc = checkexpand(bcc, addr, tblock->name, cke_hdr))
340      || subject && !(subject = checkexpand(subject, addr, tblock->name, cke_hdr))
341      || headers && !(headers = checkexpand(headers, addr, tblock->name, cke_text))
342      || text && !(text = checkexpand(text, addr, tblock->name, cke_text))
343      || file && !(file = checkexpand(file, addr, tblock->name, cke_file))
344      || logfile && !(logfile = checkexpand(logfile, addr, tblock->name, cke_file))
345      || oncelog && !(oncelog = checkexpand(oncelog, addr, tblock->name, cke_file))
346      || oncerepeat && !(oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file))
347      )
348     return FALSE;
349
350   if (oncerepeat)
351     if ((once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE)) < 0)
352       {
353       addr->transport_return = FAIL;
354       addr->message = string_sprintf("Invalid time value \"%s\" for "
355         "\"once_repeat\" in %s transport", oncerepeat, tblock->name);
356       return FALSE;
357       }
358   }
359
360 /* If the never_mail option is set, we have to scan all the recipients and
361 remove those that match. */
362
363 if (ob->never_mail)
364   {
365   const uschar *never_mail = expand_string(ob->never_mail);
366
367   if (!never_mail)
368     {
369     addr->transport_return = FAIL;
370     addr->message = string_sprintf("Failed to expand \"%s\" for "
371       "\"never_mail\" in %s transport", ob->never_mail, tblock->name);
372     return FALSE;
373     }
374
375   if (to) to = check_never_mail(to, never_mail);
376   if (cc) cc = check_never_mail(cc, never_mail);
377   if (bcc) bcc = check_never_mail(bcc, never_mail);
378
379   if (!to && !cc && !bcc)
380     {
381     DEBUG(D_transport)
382       debug_printf("*** all recipients removed by never_mail\n");
383     return OK;
384     }
385   }
386
387 /* If the -N option is set, can't do any more. */
388
389 if (f.dont_deliver)
390   {
391   DEBUG(D_transport)
392     debug_printf("*** delivery by %s transport bypassed by -N option\n",
393       tblock->name);
394   return FALSE;
395   }
396
397
398 /* If the oncelog field is set, we send want to send only one message to the
399 given recipient(s). This works only on the "To" field. If there is no "To"
400 field, the message is always sent. If the To: field contains more than one
401 recipient, the effect might not be quite as envisaged. If once_file_size is
402 set, instead of a dbm file, we use a regular file containing a circular buffer
403 recipient cache. */
404
405 if (oncelog && *oncelog && to)
406   {
407   time_t then = 0;
408
409   if (is_tainted(oncelog))
410     {
411     addr->transport_return = DEFER;
412     addr->basic_errno = EACCES;
413     addr->message = string_sprintf("Tainted '%s' (once file for %s transport)"
414       " not permitted", oncelog, tblock->name);
415     goto END_OFF;
416     }
417
418   /* Handle fixed-size cache file. */
419
420   if (ob->once_file_size > 0)
421     {
422     uschar * nextp;
423     struct stat statbuf;
424
425     cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode);
426     if (cache_fd < 0 || fstat(cache_fd, &statbuf) != 0)
427       {
428       addr->transport_return = DEFER;
429       addr->basic_errno = errno;
430       addr->message = string_sprintf("Failed to %s \"once\" file %s when "
431         "sending message from %s transport: %s",
432         cache_fd < 0 ? "open" : "stat", oncelog, tblock->name, strerror(errno));
433       goto END_OFF;
434       }
435
436     /* Get store in the temporary pool and read the entire file into it. We get
437     an amount of store that is big enough to add the new entry on the end if we
438     need to do that. */
439
440     cache_size = statbuf.st_size;
441     add_size = sizeof(time_t) + Ustrlen(to) + 1;
442     cache_buff = store_get(cache_size + add_size, oncelog);
443
444     if (read(cache_fd, cache_buff, cache_size) != cache_size)
445       {
446       addr->transport_return = DEFER;
447       addr->basic_errno = errno;
448       addr->message = US"error while reading \"once\" file";
449       goto END_OFF;
450       }
451
452     DEBUG(D_transport) debug_printf("%d bytes read from %s\n", cache_size, oncelog);
453
454     /* Scan the data for this recipient. Each entry in the file starts with
455     a time_t sized time value, followed by the address, followed by a binary
456     zero. If we find a match, put the time into "then", and the place where it
457     was found into "cache_time". Otherwise, "then" is left at zero. */
458
459     for (uschar * p = cache_buff; p < cache_buff + cache_size; p = nextp)
460       {
461       uschar *s = p + sizeof(time_t);
462       nextp = s + Ustrlen(s) + 1;
463       if (Ustrcmp(to, s) == 0)
464         {
465         memcpy(&then, p, sizeof(time_t));
466         cache_time = p;
467         break;
468         }
469       }
470     }
471
472   /* Use a DBM file for the list of previous recipients. */
473
474   else
475     {
476     EXIM_DATUM key_datum, result_datum;
477     uschar * dirname, * s;
478
479     dirname = (s = Ustrrchr(oncelog, '/'))
480       ? string_copyn(oncelog, s - oncelog) : NULL;
481     if (!(dbm_file = exim_dbopen(oncelog, dirname, O_RDWR|O_CREAT, ob->mode)))
482       {
483       addr->transport_return = DEFER;
484       addr->basic_errno = errno;
485       addr->message = string_sprintf("Failed to open %s file %s when sending "
486         "message from %s transport: %s", EXIM_DBTYPE, oncelog, tblock->name,
487         strerror(errno));
488       goto END_OFF;
489       }
490
491     exim_datum_init(&key_datum);        /* Some DBM libraries need datums */
492     exim_datum_init(&result_datum);     /* to be cleared */
493     exim_datum_data_set(&key_datum, (void *) to);
494     exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
495
496     if (exim_dbget(dbm_file, &key_datum, &result_datum))
497       {
498       /* If the datum size is that of a binary time, we are in the new world
499       where messages are sent periodically. Otherwise the file is an old one,
500       where the datum was filled with a tod_log time, which is assumed to be
501       different in size. For that, only one message is ever sent. This change
502       introduced at Exim 3.00. In a couple of years' time the test on the size
503       can be abolished. */
504
505       if (exim_datum_size_get(&result_datum) == sizeof(time_t))
506         memcpy(&then, exim_datum_data_get(&result_datum), sizeof(time_t));
507       else
508         then = now;
509       }
510     }
511
512   /* Either "then" is set zero, if no message has yet been sent, or it
513   is set to the time of the last sending. */
514
515   if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec))
516     {
517     int log_fd;
518     if (is_tainted(logfile))
519       {
520       addr->transport_return = DEFER;
521       addr->basic_errno = EACCES;
522       addr->message = string_sprintf("Tainted '%s' (logfile for %s transport)"
523         " not permitted", logfile, tblock->name);
524       goto END_OFF;
525       }
526
527     DEBUG(D_transport) debug_printf("message previously sent to %s%s\n", to,
528       (once_repeat_sec > 0)? " and repeat time not reached" : "");
529     log_fd = logfile ? Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode) : -1;
530     if (log_fd >= 0)
531       {
532       uschar *ptr = log_buffer;
533       sprintf(CS ptr, "%s\n  previously sent to %.200s\n", tod_stamp(tod_log), to);
534       while(*ptr) ptr++;
535       if(write(log_fd, log_buffer, ptr - log_buffer) != ptr-log_buffer
536         || close(log_fd))
537         DEBUG(D_transport) debug_printf("Problem writing log file %s for %s "
538           "transport\n", logfile, tblock->name);
539       }
540     goto END_OFF;
541     }
542
543   DEBUG(D_transport) debug_printf("%s %s\n", (then <= 0)?
544     "no previous message sent to" : "repeat time reached for", to);
545   }
546
547 /* We are going to send a message. Ensure any requested file is available. */
548 if (file)
549   {
550   if (is_tainted(file))
551     {
552     addr->transport_return = DEFER;
553     addr->basic_errno = EACCES;
554     addr->message = string_sprintf("Tainted '%s' (file for %s transport)"
555       " not permitted", file, tblock->name);
556     return FALSE;
557     }
558   if (!(ff = Ufopen(file, "rb")) && !ob->file_optional)
559     {
560     addr->transport_return = DEFER;
561     addr->basic_errno = errno;
562     addr->message = string_sprintf("Failed to open file %s when sending "
563       "message from %s transport: %s", file, tblock->name, strerror(errno));
564     return FALSE;
565     }
566   }
567
568 /* Make a subprocess to send the message */
569
570 if ((pid = child_open_exim(&fd, US"autoreply")) < 0)
571   {
572   /* Creation of child failed; defer this delivery. */
573
574   addr->transport_return = DEFER;
575   addr->basic_errno = errno;
576   addr->message = string_sprintf("Failed to create child process to send "
577     "message from %s transport: %s", tblock->name, strerror(errno));
578   DEBUG(D_transport) debug_printf("%s\n", addr->message);
579   if (dbm_file) exim_dbclose(dbm_file);
580   return FALSE;
581   }
582
583 /* Create the message to be sent - recipients are taken from the headers,
584 as the -t option is used. The "headers" stuff *must* be last in case there
585 are newlines in it which might, if placed earlier, screw up other headers. */
586
587 fp = fdopen(fd, "wb");
588
589 if (from) fprintf(fp, "From: %s\n", from);
590 if (reply_to) fprintf(fp, "Reply-To: %s\n", reply_to);
591 if (to) fprintf(fp, "To: %s\n", to);
592 if (cc) fprintf(fp, "Cc: %s\n", cc);
593 if (bcc) fprintf(fp, "Bcc: %s\n", bcc);
594 if (subject) fprintf(fp, "Subject: %s\n", subject);
595
596 /* Generate In-Reply-To from the message_id header; there should
597 always be one, but code defensively. */
598
599 for (h = header_list; h; h = h->next)
600   if (h->type == htype_id) break;
601
602 if (h)
603   {
604   message_id = Ustrchr(h->text, ':') + 1;
605   while (isspace(*message_id)) message_id++;
606   fprintf(fp, "In-Reply-To: %s", message_id);
607   }
608
609 moan_write_references(fp, message_id);
610
611 /* Add an Auto-Submitted: header */
612
613 fprintf(fp, "Auto-Submitted: auto-replied\n");
614
615 /* Add any specially requested headers */
616
617 if (headers) fprintf(fp, "%s\n", headers);
618 fprintf(fp, "\n");
619
620 if (text)
621   {
622   fprintf(fp, "%s", CS text);
623   if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n");
624   }
625
626 if (ff)
627   {
628   while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
629     {
630     if (file_expand)
631       {
632       uschar *s = expand_string(big_buffer);
633       DEBUG(D_transport)
634         {
635         if (!s)
636           debug_printf("error while expanding line from file:\n  %s\n  %s\n",
637             big_buffer, expand_string_message);
638         }
639       fprintf(fp, "%s", s ? CS s : CS big_buffer);
640       }
641     else fprintf(fp, "%s", CS big_buffer);
642     }
643   (void) fclose(ff);
644   }
645
646 /* Copy the original message if required, observing the return size
647 limit if we are returning the body. */
648
649 if (return_message)
650   {
651   uschar *rubric = tblock->headers_only
652     ? US"------ This is a copy of the message's header lines.\n"
653     : tblock->body_only
654     ? US"------ This is a copy of the body of the message, without the headers.\n"
655     : US"------ This is a copy of the message, including all the headers.\n";
656   transport_ctx tctx = {
657     .u = {.fd = fileno(fp)},
658     .tblock = tblock,
659     .addr = addr,
660     .check_string = NULL,
661     .escape_string =  NULL,
662     .options = (tblock->body_only ? topt_no_headers : 0)
663         | (tblock->headers_only ? topt_no_body : 0)
664         | (tblock->return_path_add ? topt_add_return_path : 0)
665         | (tblock->delivery_date_add ? topt_add_delivery_date : 0)
666         | (tblock->envelope_to_add ? topt_add_envelope_to : 0)
667         | topt_not_socket
668   };
669
670   if (bounce_return_size_limit > 0 && !tblock->headers_only)
671     {
672     struct stat statbuf;
673     int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
674       DELIVER_IN_BUFFER_SIZE;
675     if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max)
676       {
677       fprintf(fp, "\n%s"
678 "------ The body of the message is " OFF_T_FMT " characters long; only the first\n"
679 "------ %d or so are included here.\n\n", rubric, statbuf.st_size,
680         (max/1000)*1000);
681       }
682     else fprintf(fp, "\n%s\n", rubric);
683     }
684   else fprintf(fp, "\n%s\n", rubric);
685
686   fflush(fp);
687   transport_count = 0;
688   transport_write_message(&tctx, bounce_return_size_limit);
689   }
690
691 /* End the message and wait for the child process to end; no timeout. */
692
693 (void)fclose(fp);
694 rc = child_close(pid, 0);
695
696 /* Update the "sent to" log whatever the yield. This errs on the side of
697 missing out a message rather than risking sending more than one. We either have
698 cache_fd set to a fixed size, circular buffer file, or dbm_file set to an open
699 DBM file (or neither, if "once" is not set). */
700
701 /* Update fixed-size cache file. If cache_time is set, we found a previous
702 entry; that is the spot into which to put the current time. Otherwise we have
703 to add a new record; remove the first one in the file if the file is too big.
704 We always rewrite the entire file in a single write operation. This is
705 (hopefully) going to be the safest thing because there is no interlocking
706 between multiple simultaneous deliveries. */
707
708 if (cache_fd >= 0)
709   {
710   uschar *from = cache_buff;
711   int size = cache_size;
712
713   if (lseek(cache_fd, 0, SEEK_SET) == 0)
714     {
715     if (!cache_time)
716       {
717       cache_time = from + size;
718       memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
719       size += add_size;
720
721       if (cache_size > 0 && size > ob->once_file_size)
722         {
723         from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
724         size -= (from - cache_buff);
725         }
726       }
727
728     memcpy(cache_time, &now, sizeof(time_t));
729     if(write(cache_fd, from, size) != size)
730       DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
731         "transport\n", oncelog, tblock->name);
732     }
733   }
734
735 /* Update DBM file */
736
737 else if (dbm_file)
738   {
739   EXIM_DATUM key_datum, value_datum;
740   exim_datum_init(&key_datum);          /* Some DBM libraries need to have */
741   exim_datum_init(&value_datum);        /* cleared datums. */
742   exim_datum_data_set(&key_datum, to);
743   exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
744
745   /* Many OS define the datum value, sensibly, as a void *. However, there
746   are some which still have char *. By casting this address to a char * we
747   can avoid warning messages from the char * systems. */
748
749   exim_datum_data_set(&value_datum, &now);
750   exim_datum_size_set(&value_datum, sizeof(time_t));
751   exim_dbput(dbm_file, &key_datum, &value_datum);
752   }
753
754 /* If sending failed, defer to try again - but if once is set the next
755 try will skip, of course. However, if there were no recipients in the
756 message, we do not fail. */
757
758 if (rc != 0)
759   if (rc == EXIT_NORECIPIENTS)
760     {
761     DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n",
762       tblock->name);
763     }
764   else
765     {
766     addr->transport_return = DEFER;
767     addr->message = string_sprintf("Failed to send message from %s "
768       "transport (%d)", tblock->name, rc);
769     goto END_OFF;
770     }
771
772 /* Log the sending of the message if successful and required. If the file
773 fails to open, it's hard to know what to do. We cannot write to the Exim
774 log from here, since we may be running under an unprivileged uid. We don't
775 want to fail the delivery, since the message has been successfully sent. For
776 the moment, ignore open failures. Write the log entry as a single write() to a
777 file opened for appending, in order to avoid interleaving of output from
778 different processes. The log_buffer can be used exactly as for main log
779 writing. */
780
781 if (logfile)
782   {
783   int log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
784   if (log_fd >= 0)
785     {
786     gstring gs = { .size = LOG_BUFFER_SIZE, .ptr = 0, .s = log_buffer }, *g = &gs;
787
788     /* Use taint-unchecked routines for writing into log_buffer, trusting
789     that we'll never expand it. */
790
791     DEBUG(D_transport) debug_printf("logging message details\n");
792     g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "%s\n", tod_stamp(tod_log));
793     if (from)
794       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  From: %s\n", from);
795     if (to)
796       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  To: %s\n", to);
797     if (cc)
798       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Cc: %s\n", cc);
799     if (bcc)
800       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Bcc: %s\n", bcc);
801     if (subject)
802       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Subject: %s\n", subject);
803     if (headers)
804       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  %s\n", headers);
805     if(write(log_fd, g->s, g->ptr) != g->ptr || close(log_fd))
806       DEBUG(D_transport) debug_printf("Problem writing log file %s for %s "
807         "transport\n", logfile, tblock->name);
808     }
809   else DEBUG(D_transport) debug_printf("Failed to open log file %s for %s "
810     "transport: %s\n", logfile, tblock->name, strerror(errno));
811   }
812
813 END_OFF:
814 if (dbm_file) exim_dbclose(dbm_file);
815 if (cache_fd > 0) (void)close(cache_fd);
816
817 DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
818
819 return FALSE;
820 }
821
822 #endif  /*!MACRO_PREDEF*/
823 /* End of transport/autoreply.c */