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