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