Move notifier socket to general availability
[exim.git] / src / src / moan.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Functions for sending messages to sender or to mailmaster. */
9
10
11#include "exim.h"
12
13
14
0e22dfd1
PH
15/*************************************************
16* Write From: line for DSN *
17*************************************************/
18
19/* This function is called to write the From: line in automatically generated
20messages - bounces, warnings, etc. It expands a configuration item in order to
21get the text. If the expansion fails, a panic is logged and the default value
22for the option is used.
23
24Argument: the FILE to write to
25Returns: nothing
26*/
27
28void
29moan_write_from(FILE *f)
30{
d6c829b9 31uschar * s = expand_string(dsn_from);
5455f548 32if (!s)
0e22dfd1
PH
33 {
34 log_write(0, LOG_MAIN|LOG_PANIC,
35 "Failed to expand dsn_from (using default): %s", expand_string_message);
36 s = expand_string(US DEFAULT_DSN_FROM);
37 }
38fprintf(f, "From: %s\n", s);
39}
40
41
42
d6c829b9
JH
43/*************************************************
44* Write References: line for DSN *
45*************************************************/
46
47/* Generate a References: header if there is in the header_list
48at least one of Message-ID:, References:, or In-Reply-To: (see RFC 2822).
49
50Arguments: f the FILE to write to
51 message_id optional already-found message-id, or NULL
52
53Returns: nothing
54*/
55
56void
57moan_write_references(FILE * fp, uschar * message_id)
58{
59header_line * h;
60
61if (!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
69for (h = header_list; h; h = h->next)
70 if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0)
71 break;
72
73if (!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
79limit, some systems do not like headers growing beyond recognition.
80Keep the first message ID for the thread root and the last few for
81the position inside the thread, up to a maximum of 12 altogether. */
82
83if (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
059ec3d9
PH
117/*************************************************
118* Send error message *
119*************************************************/
120
121/* This function sends an error message by opening a pipe to a new process
122running Exim, and writing a message to it using the "-t" option. This is not
123used for delivery failures, which have their own code for handing failed
124addresses.
125
126Arguments:
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
135Returns: TRUE if message successfully sent
136*/
137
5455f548 138BOOL
059ec3d9
PH
139moan_send_message(uschar *recipient, int ident, error_block *eblock,
140 header_line *headers, FILE *message_file, uschar *firstline)
141{
142int written = 0;
143int fd;
144int status;
145int count = 0;
146int size_limit = bounce_return_size_limit;
8768d548 147FILE * fp;
5455f548 148int pid;
059ec3d9 149
1a2e76e1 150#ifdef SUPPORT_DMARC
5455f548
JH
151uschar * s, * s2;
152
153/* For DMARC if there is a specific sender set, expand the variable for the
154header From: and grab the address from that for the envelope FROM. */
155
156if ( 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);
164else
165 {
166 s = NULL;
167 pid = child_open_exim(&fd);
168 }
169
170#else
171pid = child_open_exim(&fd);
172#endif
059ec3d9
PH
173
174if (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 }
180else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid);
181
182/* Creation of child succeeded */
183
8768d548
JH
184fp = fdopen(fd, "wb");
185if (errors_reply_to) fprintf(fp, "Reply-To: %s\n", errors_reply_to);
186fprintf(fp, "Auto-Submitted: auto-replied\n");
5455f548 187
1a2e76e1 188#ifdef SUPPORT_DMARC
5455f548
JH
189if (s)
190 fprintf(fp, "From: %s\n", s);
191else
192#endif
193 moan_write_from(fp);
194
8768d548 195fprintf(fp, "To: %s\n", recipient);
d6c829b9 196moan_write_references(fp, NULL);
059ec3d9
PH
197
198switch(ident)
199 {
200 case ERRMESS_BADARGADDRESS:
8768d548 201 fprintf(fp,
62b7cd08 202 "Subject: Mail failure - malformed recipient address\n\n");
8768d548 203 fprintf(fp,
62b7cd08
JH
204 "A message that you sent contained a recipient address that was incorrectly\n"
205 "constructed:\n\n");
8768d548 206 fprintf(fp, " %s %s\n", eblock->text1, eblock->text2);
62b7cd08
JH
207 count = Ustrlen(eblock->text1);
208 if (count > 0 && eblock->text1[count-1] == '.')
8768d548 209 fprintf(fp,
62b7cd08 210 "\nRecipient addresses must not end with a '.' character.\n");
8768d548 211 fprintf(fp,
62b7cd08
JH
212 "\nThe message has not been delivered to any recipients.\n");
213 break;
059ec3d9
PH
214
215 case ERRMESS_BADNOADDRESS:
216 case ERRMESS_BADADDRESS:
8768d548 217 fprintf(fp,
62b7cd08 218 "Subject: Mail failure - malformed recipient address\n\n");
8768d548 219 fprintf(fp,
62b7cd08
JH
220 "A message that you sent contained one or more recipient addresses that were\n"
221 "incorrectly constructed:\n\n");
059ec3d9 222
d6c829b9 223 while (eblock)
62b7cd08 224 {
8768d548 225 fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2);
62b7cd08
JH
226 count++;
227 eblock = eblock->next;
228 }
059ec3d9 229
8768d548 230 fprintf(fp, (count == 1)? "\nThis address has been ignored. " :
62b7cd08 231 "\nThese addresses have been ignored. ");
059ec3d9 232
8768d548 233 fprintf(fp, (ident == ERRMESS_BADADDRESS)?
62b7cd08
JH
234 "The other addresses in the message were\n"
235 "syntactically valid and have been passed on for an attempt at delivery.\n" :
059ec3d9 236
62b7cd08
JH
237 "There were no other addresses in your\n"
238 "message, and so no attempt at delivery was possible.\n");
239 break;
059ec3d9
PH
240
241 case ERRMESS_IGADDRESS:
8768d548
JH
242 fprintf(fp, "Subject: Mail failure - no recipient addresses\n\n");
243 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
249
250 case ERRMESS_NOADDRESS:
8768d548
JH
251 fprintf(fp, "Subject: Mail failure - no recipient addresses\n\n");
252 fprintf(fp,
62b7cd08
JH
253 "A message that you sent contained no recipient addresses, and therefore no\n"
254 "delivery could be attempted.\n");
255 break;
059ec3d9
PH
256
257 case ERRMESS_IOERR:
8768d548
JH
258 fprintf(fp, "Subject: Mail failure - system failure\n\n");
259 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
264
265 case ERRMESS_VLONGHEADER:
8768d548
JH
266 fprintf(fp, "Subject: Mail failure - overlong header section\n\n");
267 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
272
273 case ERRMESS_VLONGHDRLINE:
8768d548
JH
274 fprintf(fp, "Subject: Mail failure - overlong header line\n\n");
275 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
280
281 case ERRMESS_TOOBIG:
8768d548
JH
282 fprintf(fp, "Subject: Mail failure - message too big\n\n");
283 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
287
288 case ERRMESS_TOOMANYRECIP:
8768d548
JH
289 fprintf(fp, "Subject: Mail failure - too many recipients\n\n");
290 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
294
295 case ERRMESS_LOCAL_SCAN:
296 case ERRMESS_LOCAL_ACL:
8768d548
JH
297 fprintf(fp, "Subject: Mail failure - rejected by local scanning code\n\n");
298 fprintf(fp,
62b7cd08
JH
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)
8768d548
JH
302 fprintf(fp, " The following error was given:\n\n %s", eblock->text1);
303 fprintf(fp, "\n");
059ec3d9
PH
304 break;
305
1a2e76e1 306#ifdef SUPPORT_DMARC
4840604e 307 case ERRMESS_DMARC_FORENSIC:
62b7cd08
JH
308 bounce_return_message = TRUE;
309 bounce_return_body = FALSE;
5455f548
JH
310 fprintf(fp, "Subject: DMARC Forensic Report for %s from IP %s\n\n",
311 eblock ? eblock->text2 : US"Unknown",
4840604e 312 sender_host_address);
8768d548 313 fprintf(fp,
62b7cd08
JH
314 "A message claiming to be from you has failed the published DMARC\n"
315 "policy for your domain.\n\n");
5455f548 316 while (eblock)
62b7cd08 317 {
8768d548 318 fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2);
62b7cd08
JH
319 count++;
320 eblock = eblock->next;
321 }
4840604e
TL
322 break;
323#endif
324
059ec3d9 325 default:
8768d548
JH
326 fprintf(fp, "Subject: Mail failure\n\n");
327 fprintf(fp,
62b7cd08
JH
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;
059ec3d9
PH
331 }
332
715ab376
PH
333/* Now, if configured, copy the message; first the headers and then the rest of
334the input if available, up to the configured limit, if the option for including
335message bodies in bounces is set. */
059ec3d9 336
715ab376 337if (bounce_return_message)
059ec3d9 338 {
715ab376
PH
339 if (bounce_return_body)
340 {
8768d548 341 fprintf(fp, "\n"
715ab376
PH
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 }
8768d548 354 fprintf(fp, "\n"
715ab376
PH
355 "------ No more than %d%s characters of the body are included.\n\n",
356 x, k);
357 }
8768d548 358 else fprintf(fp, " ------\n\n");
715ab376
PH
359 }
360 else
059ec3d9 361 {
8768d548 362 fprintf(fp, "\n"
715ab376
PH
363 "------ This is a copy of the headers that were received before the "
364 "error\n was detected.\n\n");
059ec3d9 365 }
059ec3d9 366
715ab376
PH
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. */
059ec3d9 369
62b7cd08 370 while (headers)
715ab376 371 {
8768d548 372 if (headers->text != NULL) fprintf(fp, "%s", CS headers->text);
715ab376
PH
373 headers = headers->next;
374 }
059ec3d9 375
715ab376 376 if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
8768d548 377 fputc('\n', fp);
059ec3d9 378
715ab376
PH
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. */
059ec3d9 382
62b7cd08 383 if (bounce_return_body && message_file)
059ec3d9 384 {
8768d548 385 BOOL enddot = f.dot_ends && message_file == stdin;
f3ebb786 386 uschar * buf = store_get(bounce_return_linesize_limit+2, TRUE);
62b7cd08 387
8768d548 388 if (firstline) fprintf(fp, "%s", CS firstline);
62b7cd08 389
f2cb6292 390 while (fgets(CS buf, bounce_return_linesize_limit+2, message_file))
059ec3d9 391 {
62b7cd08
JH
392 int len;
393
394 if (enddot && *buf == '.' && buf[1] == '\n')
395 {
8768d548 396 fputc('.', fp);
62b7cd08
JH
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';
8768d548 410 fputs(CS buf, fp);
62b7cd08
JH
411 break;
412 }
413
8768d548 414 fputs(CS buf, fp);
059ec3d9
PH
415 }
416 }
1a2e76e1 417#ifdef SUPPORT_DMARC
4840604e
TL
418 /* Overkill, but use exact test in case future code gets inserted */
419 else if (bounce_return_body && message_file == NULL)
420 {
62b7cd08 421 /*XXX limit line length here? */
4840604e
TL
422 /* This doesn't print newlines, disable until can parse and fix
423 * output to be legible. */
8768d548 424 fprintf(fp, "%s", expand_string(US"$message_body"));
4840604e
TL
425 }
426#endif
059ec3d9 427 }
059ec3d9
PH
428/* Close the file, which should send an EOF to the child process
429that is receiving the message. Wait for it to finish, without a timeout. */
430
8768d548 431(void)fclose(fp);
059ec3d9
PH
432status = child_close(pid, 0); /* Waits for child to close */
433if (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
444return 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
454message. Delivery failures are handled separately in deliver.c.
455
456If there is a valid sender_address, and the failing message is not a local
457error message, then this function calls moan_send_message to send a message to
458that person. If the sender's address is null, then an error has occurred with a
459message that was generated by a mailer daemon. All we can do is to write
460information to log files. The same action is taken if local_error_message is
461set - this can happen for non null-senders in certain configurations where exim
462doesn't run setuid root.
463
464Arguments:
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
472Returns: FALSE if there is no sender_address to send to;
473 else the return from moan_send_message()
474*/
475
476BOOL
477moan_to_sender(int ident, error_block *eblock, header_line *headers,
478 FILE *message_file, BOOL check_sender)
479{
480uschar *firstline = NULL;
481uschar *msg = US"Error while reading message with no usable sender address";
482
62b7cd08 483if (message_reference)
059ec3d9
PH
484 msg = string_sprintf("%s (R=%s)", msg, message_reference);
485
486/* Find the sender from a From line if permitted and possible */
487
8768d548 488if (check_sender && message_file && f.trusted_caller &&
059ec3d9
PH
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);
62b7cd08 494 if (new_sender) sender_address = new_sender;
059ec3d9
PH
495 else firstline = big_buffer;
496 }
497
498/* If viable sender address, send a message */
499
8768d548 500if (sender_address && sender_address[0] && !f.local_error_message)
059ec3d9
PH
501 return moan_send_message(sender_address, ident, eblock, headers,
502 message_file, firstline);
503
504/* Otherwise, we can only log */
505
506switch(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
558return 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
568mailmaster) about some incident.
569
570Arguments:
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
577Returns: nothing
578*/
579
580void
1ba28e2b
PP
581moan_tell_someone(uschar *who, address_item *addr,
582 const uschar *subject, const char *format, ...)
059ec3d9
PH
583{
584FILE *f;
585va_list ap;
586int fd;
587int pid = child_open_exim(&fd);
588
589if (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
596f = fdopen(fd, "wb");
456682f5 597fprintf(f, "Auto-Submitted: auto-replied\n");
0e22dfd1 598moan_write_from(f);
059ec3d9 599fprintf(f, "To: %s\n", who);
d6c829b9 600moan_write_references(f, NULL);
059ec3d9
PH
601fprintf(f, "Subject: %s\n\n", subject);
602va_start(ap, format);
603vfprintf(f, format, ap);
604va_end(ap);
605
d7978c0f 606if (addr)
059ec3d9
PH
607 {
608 fprintf(f, "\nThe following address(es) have yet to be delivered:\n");
d7978c0f 609 for (; addr; addr = addr->next)
059ec3d9 610 {
d7978c0f 611 uschar * parent = addr->parent ? addr->parent->address : NULL;
059ec3d9 612 fprintf(f, " %s", addr->address);
d7978c0f 613 if (parent) fprintf(f, " <%s>", parent);
059ec3d9 614 if (addr->basic_errno > 0) fprintf(f, ": %s", strerror(addr->basic_errno));
d7978c0f 615 if (addr->message) fprintf(f, ": %s", addr->message);
059ec3d9
PH
616 fprintf(f, "\n");
617 }
618 }
619
f1e894f3 620(void)fclose(f);
059ec3d9
PH
621child_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.
631Information is written to stdout and/or stderr, and Exim exits with a non-zero
632completion code. BSMTP is almost always called by some other program, so it is
633up to that program to interpret the return code and do something with the error
634information, and also to preserve the batch input file for human analysis.
635
636Formerly, Exim used to attempt to continue after some errors, but this strategy
637has been abandoned as it can lead to loss of messages.
638
639Arguments:
640 cmd_buffer the command causing the error, or NULL
641 format a printf() format
642 ... arguments for the format
643
644Returns: 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
649void
1ba28e2b 650moan_smtp_batch(uschar *cmd_buffer, const char *format, ...)
059ec3d9
PH
651{
652va_list ap;
653int yield = (receive_messagecount > 0)? 1 : 2;
654
655DEBUG(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
659va_start(ap, format);
660vfprintf(stdout, format, ap);
661va_end(ap);
662
663fprintf(stdout, "\nTransaction started in line %d\n",
664 bsmtp_transaction_linecount);
665fprintf(stdout, "Error detected in line %d\n", receive_linecount);
666if (cmd_buffer != NULL) fprintf(stdout, "%s\n", cmd_buffer);
667
668/* On stderr, write stuff for human consumption */
669
670fprintf(stderr,
671 "An error was detected while processing a file of BSMTP input.\n"
672 "The error message was:\n\n ");
673
674va_start(ap, format);
675vfprintf(stderr, format, ap);
676va_end(ap);
677
678fprintf(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
683if (cmd_buffer != NULL)
684 {
685 fprintf(stderr, "The SMTP command at fault was:\n\n %s\n\n",
686 cmd_buffer);
687 }
688
689fprintf(stderr, "%d previous message%s successfully processed.\n",
690 receive_messagecount, (receive_messagecount == 1)? " was" : "s were");
691
692fprintf(stderr, "The rest of the batch was abandoned.\n");
693
9bfb7e1b 694exim_exit(yield, US"batch");
059ec3d9
PH
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
705the error_copies string to see whether there is an additional recipient list to
706which errors for this recipient must be bcc'd. The incoming recipient is always
707fully qualified.
708
709Argument: recipient address
710Returns: additional recipient list or NULL
711*/
712
713uschar *
714moan_check_errorcopy(uschar *recipient)
715{
716uschar *item, *localpart, *domain;
55414b25 717const uschar *listptr = errors_copy;
059ec3d9
PH
718uschar *yield = NULL;
719uschar buffer[256];
720int sep = 0;
721int llen;
722
723if (errors_copy == NULL) return NULL;
724
725/* Set up pointer to the local part and domain, and compute the
726length of the local part. */
727
728localpart = recipient;
bc64a74d 729domain = Ustrrchr(recipient, '@');
059ec3d9
PH
730if (domain == NULL) return NULL; /* should not occur, but avoid crash */
731llen = domain++ - recipient;
732
733/* Scan through the configured items */
734
d6c829b9 735while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
059ec3d9 736 {
55414b25
JH
737 const uschar *newaddress = item;
738 const uschar *pattern = string_dequote(&newaddress);
059ec3d9
PH
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 {
ce9f225c 754 deliver_localpart = string_copyn(localpart, llen);
059ec3d9
PH
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
765DEBUG(D_any) debug_printf("errors_copy check returned %s\n",
766 (yield == NULL)? US"NULL" : yield);
767
768expand_nmax = -1;
769return 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
779or more syntax errors in the list of addresses. If there is an address to mail
780to, send a message, and always write the information to the log. In the case of
781a filter file, a "syntax error" might actually be something else, such as the
782inability to open a log file. Thus, the wording of the error message is
783general.
784
785Arguments:
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
792Returns: FALSE if string expansion failed; TRUE otherwise
793*/
794
795BOOL
796moan_skipped_syntax_errors(uschar *rname, error_block *eblock,
797 uschar *syntax_errors_to, BOOL some, uschar *custom)
798{
799int pid, fd;
800uschar *s, *t;
801FILE *f;
059ec3d9 802
d7978c0f 803for (error_block * e = eblock; e; e = e->next)
059ec3d9
PH
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);
059ec3d9 810
d7978c0f 811if (!syntax_errors_to) return TRUE;
059ec3d9 812
d7978c0f 813if (!(s = expand_string(syntax_errors_to)))
059ec3d9
PH
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
821it. */
822
823pid = child_open_exim(&fd);
824
825if (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
832f = fdopen(fd, "wb");
456682f5 833fprintf(f, "Auto-Submitted: auto-replied\n");
0e22dfd1 834moan_write_from(f);
059ec3d9
PH
835fprintf(f, "To: %s\n", s);
836fprintf(f, "Subject: error(s) in forwarding or filtering\n\n");
d6c829b9 837moan_write_references(f, NULL);
059ec3d9 838
d7978c0f 839if (custom)
059ec3d9 840 {
d7978c0f 841 if (!(t = expand_string(custom)))
059ec3d9
PH
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
850fprintf(f, "The %s router encountered the following error(s):\n\n",
851 rname);
852
d7978c0f 853for (error_block * e = eblock; e; e = e->next)
059ec3d9
PH
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
861if (some)
862 fprintf(f, "Other addresses were processed normally.\n");
863else
864 fprintf(f, "No valid addresses were generated.\n");
865
f1e894f3 866(void)fclose(f);
059ec3d9
PH
867child_close(pid, 0); /* Waits for child to close; no timeout */
868
869return TRUE;
870}
871
872/* End of moan.c */