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