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