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