Logging: server pipelining offer but no uptake
[exim.git] / src / src / moan.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Functions for sending messages to sender or to mailmaster. */
9
10
11#include "exim.h"
12
13
14
15/*************************************************
0e22dfd1
PH
16* Write From: line for DSN *
17*************************************************/
18
19/* This function is called to write the From: line in automatically generated
20messages - bounces, warnings, etc. It expands a configuration item in order to
21get the text. If the expansion fails, a panic is logged and the default value
22for the option is used.
23
24Argument: the FILE to write to
25Returns: nothing
26*/
27
28void
29moan_write_from(FILE *f)
30{
31uschar *s = expand_string(dsn_from);
32if (s == NULL)
33 {
34 log_write(0, LOG_MAIN|LOG_PANIC,
35 "Failed to expand dsn_from (using default): %s", expand_string_message);
36 s = expand_string(US DEFAULT_DSN_FROM);
37 }
38fprintf(f, "From: %s\n", s);
39}
40
41
42
43/*************************************************
059ec3d9
PH
44* Send error message *
45*************************************************/
46
47/* This function sends an error message by opening a pipe to a new process
48running Exim, and writing a message to it using the "-t" option. This is not
49used for delivery failures, which have their own code for handing failed
50addresses.
51
52Arguments:
53 recipient addressee for the message
54 ident identifies the type of error
55 eblock chain of error_blocks containing data about the error
56 headers the message's headers
57 message_file FILE containing the body of the message
58 firstline contains first line of file, if it was read to check for
59 "From ", but it turned out not to be
60
61Returns: TRUE if message successfully sent
62*/
63
64static BOOL
65moan_send_message(uschar *recipient, int ident, error_block *eblock,
66 header_line *headers, FILE *message_file, uschar *firstline)
67{
68int written = 0;
69int fd;
70int status;
71int count = 0;
72int size_limit = bounce_return_size_limit;
73FILE *f;
74int pid = child_open_exim(&fd);
75
76/* Creation of child failed */
77
78if (pid < 0)
79 {
80 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
81 strerror(errno));
82 return FALSE;
83 }
84else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid);
85
86/* Creation of child succeeded */
87
88f = fdopen(fd, "wb");
62b7cd08 89if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to);
456682f5 90fprintf(f, "Auto-Submitted: auto-replied\n");
0e22dfd1 91moan_write_from(f);
059ec3d9
PH
92fprintf(f, "To: %s\n", recipient);
93
94switch(ident)
95 {
96 case ERRMESS_BADARGADDRESS:
059ec3d9 97 fprintf(f,
62b7cd08
JH
98 "Subject: Mail failure - malformed recipient address\n\n");
99 fprintf(f,
100 "A message that you sent contained a recipient address that was incorrectly\n"
101 "constructed:\n\n");
102 fprintf(f, " %s %s\n", eblock->text1, eblock->text2);
103 count = Ustrlen(eblock->text1);
104 if (count > 0 && eblock->text1[count-1] == '.')
105 fprintf(f,
106 "\nRecipient addresses must not end with a '.' character.\n");
107 fprintf(f,
108 "\nThe message has not been delivered to any recipients.\n");
109 break;
059ec3d9
PH
110
111 case ERRMESS_BADNOADDRESS:
112 case ERRMESS_BADADDRESS:
62b7cd08
JH
113 fprintf(f,
114 "Subject: Mail failure - malformed recipient address\n\n");
115 fprintf(f,
116 "A message that you sent contained one or more recipient addresses that were\n"
117 "incorrectly constructed:\n\n");
059ec3d9 118
62b7cd08
JH
119 while (eblock != NULL)
120 {
121 fprintf(f, " %s: %s\n", eblock->text1, eblock->text2);
122 count++;
123 eblock = eblock->next;
124 }
059ec3d9 125
62b7cd08
JH
126 fprintf(f, (count == 1)? "\nThis address has been ignored. " :
127 "\nThese addresses have been ignored. ");
059ec3d9 128
62b7cd08
JH
129 fprintf(f, (ident == ERRMESS_BADADDRESS)?
130 "The other addresses in the message were\n"
131 "syntactically valid and have been passed on for an attempt at delivery.\n" :
059ec3d9 132
62b7cd08
JH
133 "There were no other addresses in your\n"
134 "message, and so no attempt at delivery was possible.\n");
135 break;
059ec3d9
PH
136
137 case ERRMESS_IGADDRESS:
62b7cd08
JH
138 fprintf(f, "Subject: Mail failure - no recipient addresses\n\n");
139 fprintf(f,
140 "A message that you sent using the -t command line option contained no\n"
141 "addresses that were not also on the command line, and were therefore\n"
142 "suppressed. This left no recipient addresses, and so no delivery could\n"
143 "be attempted.\n");
144 break;
059ec3d9
PH
145
146 case ERRMESS_NOADDRESS:
62b7cd08
JH
147 fprintf(f, "Subject: Mail failure - no recipient addresses\n\n");
148 fprintf(f,
149 "A message that you sent contained no recipient addresses, and therefore no\n"
150 "delivery could be attempted.\n");
151 break;
059ec3d9
PH
152
153 case ERRMESS_IOERR:
62b7cd08
JH
154 fprintf(f, "Subject: Mail failure - system failure\n\n");
155 fprintf(f,
156 "A system failure was encountered while processing a message that you sent,\n"
157 "so it has not been possible to deliver it. The error was:\n\n%s\n",
158 eblock->text1);
159 break;
059ec3d9
PH
160
161 case ERRMESS_VLONGHEADER:
62b7cd08
JH
162 fprintf(f, "Subject: Mail failure - overlong header section\n\n");
163 fprintf(f,
164 "A message that you sent contained a header section that was excessively\n"
165 "long and could not be handled by the mail transmission software. The\n"
166 "message has not been delivered to any recipients.\n");
167 break;
059ec3d9
PH
168
169 case ERRMESS_VLONGHDRLINE:
62b7cd08
JH
170 fprintf(f, "Subject: Mail failure - overlong header line\n\n");
171 fprintf(f,
172 "A message that you sent contained a header line that was excessively\n"
173 "long and could not be handled by the mail transmission software. The\n"
174 "message has not been delivered to any recipients.\n");
175 break;
059ec3d9
PH
176
177 case ERRMESS_TOOBIG:
62b7cd08
JH
178 fprintf(f, "Subject: Mail failure - message too big\n\n");
179 fprintf(f,
180 "A message that you sent was longer than the maximum size allowed on this\n"
181 "system. It was not delivered to any recipients.\n");
182 break;
059ec3d9
PH
183
184 case ERRMESS_TOOMANYRECIP:
62b7cd08
JH
185 fprintf(f, "Subject: Mail failure - too many recipients\n\n");
186 fprintf(f,
187 "A message that you sent contained more recipients than allowed on this\n"
188 "system. It was not delivered to any recipients.\n");
189 break;
059ec3d9
PH
190
191 case ERRMESS_LOCAL_SCAN:
192 case ERRMESS_LOCAL_ACL:
62b7cd08 193 fprintf(f, "Subject: Mail failure - rejected by local scanning code\n\n");
059ec3d9 194 fprintf(f,
62b7cd08
JH
195 "A message that you sent was rejected by the local scanning code that\n"
196 "checks incoming messages on this system.");
197 if (eblock->text1)
198 fprintf(f, " The following error was given:\n\n %s", eblock->text1);
059ec3d9
PH
199 fprintf(f, "\n");
200 break;
201
4840604e
TL
202#ifdef EXPERIMENTAL_DMARC
203 case ERRMESS_DMARC_FORENSIC:
62b7cd08
JH
204 bounce_return_message = TRUE;
205 bounce_return_body = FALSE;
206 fprintf(f,
4840604e
TL
207 "Subject: DMARC Forensic Report for %s from IP %s\n\n",
208 ((eblock == NULL) ? US"Unknown" : eblock->text2),
209 sender_host_address);
62b7cd08
JH
210 fprintf(f,
211 "A message claiming to be from you has failed the published DMARC\n"
212 "policy for your domain.\n\n");
213 while (eblock != NULL)
214 {
215 fprintf(f, " %s: %s\n", eblock->text1, eblock->text2);
216 count++;
217 eblock = eblock->next;
218 }
4840604e
TL
219 break;
220#endif
221
059ec3d9 222 default:
62b7cd08
JH
223 fprintf(f, "Subject: Mail failure\n\n");
224 fprintf(f,
225 "A message that you sent has caused the error routine to be entered with\n"
226 "an unknown error number (%d).\n", ident);
227 break;
059ec3d9
PH
228 }
229
715ab376
PH
230/* Now, if configured, copy the message; first the headers and then the rest of
231the input if available, up to the configured limit, if the option for including
232message bodies in bounces is set. */
059ec3d9 233
715ab376 234if (bounce_return_message)
059ec3d9 235 {
715ab376
PH
236 if (bounce_return_body)
237 {
238 fprintf(f, "\n"
239 "------ This is a copy of your message, including all the headers.");
240 if (size_limit == 0 || size_limit > thismessage_size_limit)
241 size_limit = thismessage_size_limit;
242 if (size_limit > 0 && size_limit < message_size)
243 {
244 int x = size_limit;
245 uschar *k = US"";
246 if ((x & 1023) == 0)
247 {
248 k = US"K";
249 x >>= 10;
250 }
251 fprintf(f, "\n"
252 "------ No more than %d%s characters of the body are included.\n\n",
253 x, k);
254 }
255 else fprintf(f, " ------\n\n");
256 }
257 else
059ec3d9 258 {
715ab376
PH
259 fprintf(f, "\n"
260 "------ This is a copy of the headers that were received before the "
261 "error\n was detected.\n\n");
059ec3d9 262 }
059ec3d9 263
715ab376
PH
264 /* If the error occurred before the Received: header was created, its text
265 field will still be NULL; just omit such a header line. */
059ec3d9 266
62b7cd08 267 while (headers)
715ab376
PH
268 {
269 if (headers->text != NULL) fprintf(f, "%s", CS headers->text);
270 headers = headers->next;
271 }
059ec3d9 272
715ab376
PH
273 if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
274 fputc('\n', f);
059ec3d9 275
715ab376
PH
276 /* After early detection of an error, the message file may be STDIN,
277 in which case we might have to terminate on a line containing just "."
278 as well as on EOF. We may already have the first line in memory. */
059ec3d9 279
62b7cd08 280 if (bounce_return_body && message_file)
059ec3d9 281 {
715ab376 282 BOOL enddot = dot_ends && message_file == stdin;
62b7cd08
JH
283 uschar * buf = store_get(bounce_return_linesize_limit+2);
284
285 if (firstline) fprintf(f, "%s", CS firstline);
286
f2cb6292 287 while (fgets(CS buf, bounce_return_linesize_limit+2, message_file))
059ec3d9 288 {
62b7cd08
JH
289 int len;
290
291 if (enddot && *buf == '.' && buf[1] == '\n')
292 {
293 fputc('.', f);
294 break;
295 }
296
297 len = Ustrlen(buf);
298 if (buf[len-1] != '\n')
299 { /* eat rest of partial line */
300 int ch;
301 while ((ch = fgetc(message_file)) != EOF && ch != '\n') ;
302 }
303
304 if (size_limit > 0 && len > size_limit - written)
305 {
306 buf[size_limit - written] = '\0';
f2cb6292 307 fputs(CS buf, f);
62b7cd08
JH
308 break;
309 }
310
f2cb6292 311 fputs(CS buf, f);
059ec3d9
PH
312 }
313 }
4840604e
TL
314#ifdef EXPERIMENTAL_DMARC
315 /* Overkill, but use exact test in case future code gets inserted */
316 else if (bounce_return_body && message_file == NULL)
317 {
62b7cd08 318 /*XXX limit line length here? */
4840604e
TL
319 /* This doesn't print newlines, disable until can parse and fix
320 * output to be legible. */
321 fprintf(f, "%s", expand_string(US"$message_body"));
322 }
323#endif
059ec3d9 324 }
059ec3d9
PH
325/* Close the file, which should send an EOF to the child process
326that is receiving the message. Wait for it to finish, without a timeout. */
327
f1e894f3 328(void)fclose(f);
059ec3d9
PH
329status = child_close(pid, 0); /* Waits for child to close */
330if (status != 0)
331 {
332 uschar *msg = US"Child mail process returned status";
333 if (status == -257)
334 log_write(0, LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno,
335 strerror(errno));
336 else
337 log_write(0, LOG_MAIN, "%s %d", msg, status);
338 return FALSE;
339 }
340
341return TRUE;
342}
343
344
345
346/*************************************************
347* Send message to sender *
348*************************************************/
349
350/* This function is called when errors are detected during the receipt of a
351message. Delivery failures are handled separately in deliver.c.
352
353If there is a valid sender_address, and the failing message is not a local
354error message, then this function calls moan_send_message to send a message to
355that person. If the sender's address is null, then an error has occurred with a
356message that was generated by a mailer daemon. All we can do is to write
357information to log files. The same action is taken if local_error_message is
358set - this can happen for non null-senders in certain configurations where exim
359doesn't run setuid root.
360
361Arguments:
362 ident identifies the particular error
363 eblock chain of error_blocks containing data about the error
364 headers message's headers (chain)
365 message_file a FILE where the body of the message can be read
366 check_sender if TRUE, read the first line of the file for a possible
367 "From " sender (if a trusted caller)
368
369Returns: FALSE if there is no sender_address to send to;
370 else the return from moan_send_message()
371*/
372
373BOOL
374moan_to_sender(int ident, error_block *eblock, header_line *headers,
375 FILE *message_file, BOOL check_sender)
376{
377uschar *firstline = NULL;
378uschar *msg = US"Error while reading message with no usable sender address";
379
62b7cd08 380if (message_reference)
059ec3d9
PH
381 msg = string_sprintf("%s (R=%s)", msg, message_reference);
382
383/* Find the sender from a From line if permitted and possible */
384
62b7cd08 385if (check_sender && message_file && trusted_caller &&
059ec3d9
PH
386 Ufgets(big_buffer, BIG_BUFFER_SIZE, message_file) != NULL)
387 {
388 uschar *new_sender = NULL;
389 if (regex_match_and_setup(regex_From, big_buffer, 0, -1))
390 new_sender = expand_string(uucp_from_sender);
62b7cd08 391 if (new_sender) sender_address = new_sender;
059ec3d9
PH
392 else firstline = big_buffer;
393 }
394
395/* If viable sender address, send a message */
396
62b7cd08 397if (sender_address && sender_address[0] && !local_error_message)
059ec3d9
PH
398 return moan_send_message(sender_address, ident, eblock, headers,
399 message_file, firstline);
400
401/* Otherwise, we can only log */
402
403switch(ident)
404 {
405 case ERRMESS_BADARGADDRESS:
406 case ERRMESS_BADNOADDRESS:
407 case ERRMESS_BADADDRESS:
408 log_write(0, LOG_MAIN, "%s: at least one malformed recipient address: "
409 "%s - %s", msg, eblock->text1, eblock->text2);
410 break;
411
412 case ERRMESS_IGADDRESS:
413 case ERRMESS_NOADDRESS:
414 log_write(0, LOG_MAIN, "%s: no recipient addresses", msg);
415 break;
416
417 /* This error has already been logged. */
418 case ERRMESS_IOERR:
419 break;
420
421 case ERRMESS_VLONGHEADER:
422 log_write(0, LOG_MAIN, "%s: excessively long message header section read "
423 "(more than %d characters)", msg, header_maxsize);
424 break;
425
426 case ERRMESS_VLONGHDRLINE:
427 log_write(0, LOG_MAIN, "%s: excessively long message header line read "
428 "(more than %d characters)", msg, header_line_maxsize);
429 break;
430
431 case ERRMESS_TOOBIG:
432 log_write(0, LOG_MAIN, "%s: message too big (limit set to %d)", msg,
433 thismessage_size_limit);
434 break;
435
436 case ERRMESS_TOOMANYRECIP:
437 log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg,
438 recipients_max);
439 break;
440
441 case ERRMESS_LOCAL_SCAN:
442 log_write(0, LOG_MAIN, "%s: rejected by local_scan: %s", msg, eblock->text1);
443 break;
444
445 case ERRMESS_LOCAL_ACL:
446 log_write(0, LOG_MAIN, "%s: rejected by non-SMTP ACL: %s", msg, eblock->text1);
447 break;
448
449 default:
450 log_write(0, LOG_MAIN|LOG_PANIC, "%s: unknown error number %d", msg,
451 ident);
452 break;
453 }
454
455return FALSE;
456}
457
458
459
460/*************************************************
461* Send message to someone *
462*************************************************/
463
464/* This is called when exim is configured to tell someone (often the
465mailmaster) about some incident.
466
467Arguments:
468 who address to send mail to
469 addr chain of deferred addresses whose details are to be included
470 subject subject text for the message
471 format a printf() format for the body of the message
472 ... arguments for the format
473
474Returns: nothing
475*/
476
477void
1ba28e2b
PP
478moan_tell_someone(uschar *who, address_item *addr,
479 const uschar *subject, const char *format, ...)
059ec3d9
PH
480{
481FILE *f;
482va_list ap;
483int fd;
484int pid = child_open_exim(&fd);
485
486if (pid < 0)
487 {
488 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
489 strerror(errno));
490 return;
491 }
492
493f = fdopen(fd, "wb");
456682f5 494fprintf(f, "Auto-Submitted: auto-replied\n");
0e22dfd1 495moan_write_from(f);
059ec3d9
PH
496fprintf(f, "To: %s\n", who);
497fprintf(f, "Subject: %s\n\n", subject);
498va_start(ap, format);
499vfprintf(f, format, ap);
500va_end(ap);
501
502if (addr != NULL)
503 {
504 fprintf(f, "\nThe following address(es) have yet to be delivered:\n");
505 for (; addr != NULL; addr = addr->next)
506 {
507 uschar *parent = (addr->parent == NULL)? NULL : addr->parent->address;
508 fprintf(f, " %s", addr->address);
509 if (parent != NULL) fprintf(f, " <%s>", parent);
510 if (addr->basic_errno > 0) fprintf(f, ": %s", strerror(addr->basic_errno));
511 if (addr->message != NULL) fprintf(f, ": %s", addr->message);
512 fprintf(f, "\n");
513 }
514 }
515
f1e894f3 516(void)fclose(f);
059ec3d9
PH
517child_close(pid, 0); /* Waits for child to close; no timeout */
518}
519
520
521
522/*************************************************
523* Handle SMTP batch error *
524*************************************************/
525
526/* This is called when something goes wrong in batched (-bS) SMTP input.
527Information is written to stdout and/or stderr, and Exim exits with a non-zero
528completion code. BSMTP is almost always called by some other program, so it is
529up to that program to interpret the return code and do something with the error
530information, and also to preserve the batch input file for human analysis.
531
532Formerly, Exim used to attempt to continue after some errors, but this strategy
533has been abandoned as it can lead to loss of messages.
534
535Arguments:
536 cmd_buffer the command causing the error, or NULL
537 format a printf() format
538 ... arguments for the format
539
540Returns: does not return; exits from the program
541 exit code = 1 if some messages were accepted
542 exit code = 2 if no messages were accepted
543*/
544
545void
1ba28e2b 546moan_smtp_batch(uschar *cmd_buffer, const char *format, ...)
059ec3d9
PH
547{
548va_list ap;
549int yield = (receive_messagecount > 0)? 1 : 2;
550
551DEBUG(D_any) debug_printf("Handling error in batched SMTP input\n");
552
553/* On stdout, write stuff that a program could parse fairly easily. */
554
555va_start(ap, format);
556vfprintf(stdout, format, ap);
557va_end(ap);
558
559fprintf(stdout, "\nTransaction started in line %d\n",
560 bsmtp_transaction_linecount);
561fprintf(stdout, "Error detected in line %d\n", receive_linecount);
562if (cmd_buffer != NULL) fprintf(stdout, "%s\n", cmd_buffer);
563
564/* On stderr, write stuff for human consumption */
565
566fprintf(stderr,
567 "An error was detected while processing a file of BSMTP input.\n"
568 "The error message was:\n\n ");
569
570va_start(ap, format);
571vfprintf(stderr, format, ap);
572va_end(ap);
573
574fprintf(stderr,
575 "\n\nThe SMTP transaction started in line %d.\n"
576 "The error was detected in line %d.\n",
577 bsmtp_transaction_linecount, receive_linecount);
578
579if (cmd_buffer != NULL)
580 {
581 fprintf(stderr, "The SMTP command at fault was:\n\n %s\n\n",
582 cmd_buffer);
583 }
584
585fprintf(stderr, "%d previous message%s successfully processed.\n",
586 receive_messagecount, (receive_messagecount == 1)? " was" : "s were");
587
588fprintf(stderr, "The rest of the batch was abandoned.\n");
589
9bfb7e1b 590exim_exit(yield, US"batch");
059ec3d9
PH
591}
592
593
594
595
596/*************************************************
597* Check for error copies *
598*************************************************/
599
600/* This function is passed the recipient of an error message, and must check
601the error_copies string to see whether there is an additional recipient list to
602which errors for this recipient must be bcc'd. The incoming recipient is always
603fully qualified.
604
605Argument: recipient address
606Returns: additional recipient list or NULL
607*/
608
609uschar *
610moan_check_errorcopy(uschar *recipient)
611{
612uschar *item, *localpart, *domain;
55414b25 613const uschar *listptr = errors_copy;
059ec3d9
PH
614uschar *yield = NULL;
615uschar buffer[256];
616int sep = 0;
617int llen;
618
619if (errors_copy == NULL) return NULL;
620
621/* Set up pointer to the local part and domain, and compute the
622length of the local part. */
623
624localpart = recipient;
bc64a74d 625domain = Ustrrchr(recipient, '@');
059ec3d9
PH
626if (domain == NULL) return NULL; /* should not occur, but avoid crash */
627llen = domain++ - recipient;
628
629/* Scan through the configured items */
630
631while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer)))
632 != NULL)
633 {
55414b25
JH
634 const uschar *newaddress = item;
635 const uschar *pattern = string_dequote(&newaddress);
059ec3d9
PH
636
637 /* If no new address found, just skip this item. */
638
639 while (isspace(*newaddress)) newaddress++;
640 if (*newaddress == 0) continue;
641
642 /* We now have an item to match as an address in item, and the additional
643 address in newaddress. If the pattern matches, expand the new address string
644 and return it. During expansion, make local part and domain available for
645 insertion. This requires a copy to be made; we can't just temporarily
646 terminate it, as the whole address is required for $0. */
647
648 if (match_address_list(recipient, TRUE, TRUE, &pattern, NULL, 0, UCHAR_MAX+1,
649 NULL) == OK)
650 {
ce9f225c 651 deliver_localpart = string_copyn(localpart, llen);
059ec3d9
PH
652 deliver_domain = domain;
653 yield = expand_string_copy(newaddress);
654 deliver_domain = deliver_localpart = NULL;
655 if (yield == NULL)
656 log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %s when processing "
657 "errors_copy: %s", newaddress, expand_string_message);
658 break;
659 }
660 }
661
662DEBUG(D_any) debug_printf("errors_copy check returned %s\n",
663 (yield == NULL)? US"NULL" : yield);
664
665expand_nmax = -1;
666return yield;
667}
668
669
670
671/************************************************
672* Handle skipped syntax errors *
673************************************************/
674
675/* This function is called by the redirect router when it has skipped over one
676or more syntax errors in the list of addresses. If there is an address to mail
677to, send a message, and always write the information to the log. In the case of
678a filter file, a "syntax error" might actually be something else, such as the
679inability to open a log file. Thus, the wording of the error message is
680general.
681
682Arguments:
683 rname the router name
684 eblock chain of error blocks
685 syntax_errors_to address to send mail to, or NULL
686 some TRUE if some addresses were generated; FALSE if none were
687 custom custom message text
688
689Returns: FALSE if string expansion failed; TRUE otherwise
690*/
691
692BOOL
693moan_skipped_syntax_errors(uschar *rname, error_block *eblock,
694 uschar *syntax_errors_to, BOOL some, uschar *custom)
695{
696int pid, fd;
697uschar *s, *t;
698FILE *f;
699error_block *e;
700
701for (e = eblock; e != NULL; e = e->next)
702 {
703 if (e->text2 != NULL)
704 log_write(0, LOG_MAIN, "%s router: skipped error: %s in \"%s\"",
705 rname, e->text1, e->text2);
706 else
707 log_write(0, LOG_MAIN, "%s router: skipped error: %s", rname,
708 e->text1);
709 }
710
711if (syntax_errors_to == NULL) return TRUE;
712
713s = expand_string(syntax_errors_to);
714if (s == NULL)
715 {
716 log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname,
717 syntax_errors_to, expand_string_message);
718 return FALSE;
719 }
720
721/* If we can't create a process to send the message, just forget about
722it. */
723
724pid = child_open_exim(&fd);
725
726if (pid < 0)
727 {
728 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
729 strerror(errno));
730 return TRUE;
731 }
732
733f = fdopen(fd, "wb");
456682f5 734fprintf(f, "Auto-Submitted: auto-replied\n");
0e22dfd1 735moan_write_from(f);
059ec3d9
PH
736fprintf(f, "To: %s\n", s);
737fprintf(f, "Subject: error(s) in forwarding or filtering\n\n");
738
739if (custom != NULL)
740 {
741 t = expand_string(custom);
742 if (t == NULL)
743 {
744 log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname,
745 custom, expand_string_message);
746 return FALSE;
747 }
748 fprintf(f, "%s\n\n", t);
749 }
750
751fprintf(f, "The %s router encountered the following error(s):\n\n",
752 rname);
753
754for (e = eblock; e != NULL; e = e->next)
755 {
756 fprintf(f, " %s", e->text1);
757 if (e->text2 != NULL)
758 fprintf(f, " in the address\n \"%s\"", e->text2);
759 fprintf(f, "\n\n");
760 }
761
762if (some)
763 fprintf(f, "Other addresses were processed normally.\n");
764else
765 fprintf(f, "No valid addresses were generated.\n");
766
f1e894f3 767(void)fclose(f);
059ec3d9
PH
768child_close(pid, 0); /* Waits for child to close; no timeout */
769
770return TRUE;
771}
772
773/* End of moan.c */