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