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