]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20000924
authorWietse Venema <wietse@porcupine.org>
Sun, 24 Sep 2000 00:00:00 +0000 (00:00 +0000)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:26:47 +0000 (06:26 +0000)
23 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/bounce.8.html
postfix/man/man8/bounce.8
postfix/src/bounce/Makefile.in
postfix/src/bounce/bounce.c
postfix/src/bounce/bounce_notify_service.c
postfix/src/bounce/bounce_notify_util.c [new file with mode: 0644]
postfix/src/bounce/bounce_recip_service.c [deleted file]
postfix/src/bounce/bounce_service.h
postfix/src/cleanup/cleanup_api.c
postfix/src/global/Makefile.in
postfix/src/global/bounce.c
postfix/src/global/bounce.h
postfix/src/global/bounce_log.c [new file with mode: 0644]
postfix/src/global/bounce_log.h [new file with mode: 0644]
postfix/src/global/mail_version.h
postfix/src/global/xtext.c [new file with mode: 0644]
postfix/src/global/xtext.h [new file with mode: 0644]
postfix/src/showq/Makefile.in
postfix/src/showq/showq.c
postfix/src/util/sys_defs.h

index 005b2559e8634546c14bbf7f9610c2352cdea9b6..ca739a89cd48104ee88645275a9c33400455b960 100644 (file)
@@ -5,6 +5,8 @@
 -TBINATTR_INFO
 -TBINHASH
 -TBINHASH_INFO
+-TBOUNCE_INFO
+-TBOUNCE_LOG
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
index e328ae595049c60b095d418a8330c546b0ecb07e..c8c9a95969b88dcdf852ba784d5abf2d3f8f0b11 100644 (file)
@@ -4256,8 +4256,8 @@ Apologies for any names omitted.
        Portability: MacOSX hints and tips by Joe Block, University
        of Central Florida School of Optics/CREOL
 
-       The MacOSX gcc compiler does not understand the new
-       printf_like/scanf_like attributes. File: util/sys_defs.h.
+       Portability: The MacOSX gcc compiler does not understand
+       the new printf_like/scanf_like attributes. File: util/sys_defs.h.
 
 20000922
 
@@ -4270,3 +4270,25 @@ Apologies for any names omitted.
        still logged with the default syslog facility, as are errors
        while processing the main.cf file (surprise).  Based on
        code by Andrew McNamara.
+
+20000923
+
+       Cleanup: new bounce logfile API so that Postfix can change
+       to an extensible bounce logfile format with per-recipient
+       sender addresses (needed for VERP and for reporting local
+       list delivery problems to the list owner) and other
+       attributes.  File:  global/bounce_log.[hc].
+
+       Cleanup: replaced the ad-hoc logfile parsing code in showq
+       by something that uses the generic bounce logfile API.
+
+20000924
+
+       Feature: Postfix bounced mail and delayed mail notifications
+       now have the standard RFC 1894 form (DSN). The bounce
+       service now uses the's generic bounce logfile API.  File:
+       bounce/bounce_notify_service.c, bounce/bounce_notify_util.c.
+
+       Cleanup: deleted the per-recipient bounce protocol.  Future
+       bounce logfiles will support per-recipient bounce addresses.
+       Files:  global/bounce.c, bounce/bounce_recip_service.
index 746938cfe63068481ff4b16582e96e6692cef968..5c88e92a54fb3eaba1138d9819a2c665ef778f7d 100644 (file)
@@ -1,3 +1,17 @@
+Incompatible changes with snapshot-20000924
+===========================================
+
+The postmaster address in the "sorry" text at the top of bounced
+mail is now just postmaster, not postmaster@sending.machine.  The
+idea is to refer users to their own postmaster.
+
+Major changes with snapshot-20000924
+====================================
+
+DSN formatted bounced/delayed mail notifications, finally.  The
+human-readable text still exists, so that users will not have to
+be unnecessarily confused by all the ugliness of RFC 1894.
+
 Major changes with snapshot-20000923
 ====================================
 
index a4d8be3c08731f7a21a610acff60b09f3386ac36..63e760535e6355bf724fcfe6efdbadfea59a0bfd 100644 (file)
@@ -28,36 +28,36 @@ BOUNCE(8)                                               BOUNCE(8)
               and  of  the corresponding message. When the bounce
               is posted successfully, the log file is deleted.
 
-       <b>o</b>      Post a bounce message without accessing a  per-mes-
-              sage log file.
-
-       The  software does a best effort to notify the sender that
-       there was a problem. A notification is sent even when  the
+       The software does a best effort to notify the sender  that
+       there  was a problem. A notification is sent even when the
        log file or original message cannot be read.
 
-       Optionally,  a client can request that the per-message log
-       file be deleted when the requested operation fails.   This
+       Optionally, a client can request that the per-message  log
+       file  be deleted when the requested operation fails.  This
        is used by clients that cannot retry transactions by them-
-       selves, and that  depend  on  retry  logic  in  their  own
+       selves,  and  that  depend  on  retry  logic  in their own
        client.
 
 <b>STANDARDS</b>
-       RFC 822 (ARPA Internet Text Messages)
+       <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
+       <a href="http://www.faqs.org/rfcs/rfc1894.html">RFC 1894</a> (Delivery Status Notifications)
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to <b>syslogd</b>(8).
 
 <b>BUGS</b>
-       The  log  files  use  an ad-hoc, unstructured format. This
-       will have to change in order to  easily  support  standard
+       The log files use an  ad-hoc,  unstructured  format.  This
+       will  have  to  change in order to easily support standard
        delivery status notifications.
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The  following  <b>main.cf</b> parameters are especially relevant
-       to this program. See the Postfix <b>main.cf</b> file  for  syntax
-       details  and  for  default  values. Use the <b>postfix</b> <b>reload</b>
+       The following <b>main.cf</b> parameters are  especially  relevant
+       to  this  program. See the Postfix <b>main.cf</b> file for syntax
+       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
        command after a configuration change.
 
+       <b>bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
+              The  recipient of single bounce postmaster notices.
 
 
 
@@ -71,26 +71,23 @@ BOUNCE(8)                                               BOUNCE(8)
 BOUNCE(8)                                               BOUNCE(8)
 
 
-       <b>bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              The recipient of single bounce postmaster  notices.
-
        <b>2bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              The  recipient of double bounce postmaster notices.
+              The recipient of double bounce postmaster  notices.
 
        <b>delay</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
               The recipient of "delayed mail" postmaster notices.
 
        <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
-              Limit  the  amount of original message context that
+              Limit the amount of original message  context  that
               is sent in a non-delivery notification.
 
        <b>mail</b><i>_</i><b>name</b>
-              Use this mail system name in the introductory  text
+              Use  this mail system name in the introductory text
               at the start of a bounce message.
 
        <b>notify</b><i>_</i><b>classes</b>
-              Notify  the  postmaster  of  bounced mail when this
-              parameter includes the <b>bounce</b>  class.  For  privacy
+              Notify the postmaster of  bounced  mail  when  this
+              parameter  includes  the  <b>bounce</b> class. For privacy
               reasons, the message body is not included.
 
 <b>SEE</b> <b>ALSO</b>
@@ -99,7 +96,7 @@ BOUNCE(8)                                               BOUNCE(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
@@ -124,6 +121,9 @@ BOUNCE(8)                                               BOUNCE(8)
 
 
 
+
+
+
 
 
 
index 59c98af64cda8a1edcd175785bc708997e94c504..02dc4cee6a79630eea38c4c5f1e236a180d99a43 100644 (file)
@@ -27,8 +27,6 @@ Append a recipient status record to a per-message log file.
 Post a bounce message, with a copy of a log file and of the
 corresponding message. When the bounce is posted successfully,
 the log file is deleted.
-.IP \(bu
-Post a bounce message without accessing a per-message log file.
 .PP
 The software does a best effort to notify the sender that there
 was a problem. A notification is sent even when the log file
@@ -42,6 +40,7 @@ themselves, and that depend on retry logic in their own client.
 .na
 .nf
 RFC 822 (ARPA Internet Text Messages)
+RFC 1894 (Delivery Status Notifications)
 .SH DIAGNOSTICS
 .ad
 .fi
index 1b0943545ba73b684df7a9f798733dd60d196c55..97bb71431f82dbd66a7a0d469c17108e779a98b7 100644 (file)
@@ -1,8 +1,8 @@
 SHELL  = /bin/sh
 SRCS   = bounce.c bounce_append_service.c bounce_notify_service.c \
-       bounce_recip_service.c bounce_cleanup.c
+       bounce_cleanup.c bounce_notify_util.c
 OBJS   = bounce.o bounce_append_service.o bounce_notify_service.o \
-       bounce_recip_service.o bounce_cleanup.o
+       bounce_cleanup.o bounce_notify_util.o
 HDRS   = 
 TESTSRC        = 
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -71,6 +71,7 @@ bounce.o: ../../include/mail_conf.h
 bounce.o: ../../include/bounce.h
 bounce.o: ../../include/mail_server.h
 bounce.o: bounce_service.h
+bounce.o: ../../include/bounce_log.h
 bounce_append_service.o: bounce_append_service.c
 bounce_append_service.o: ../../include/sys_defs.h
 bounce_append_service.o: ../../include/msg.h
@@ -82,6 +83,7 @@ bounce_append_service.o: ../../include/mail_queue.h
 bounce_append_service.o: ../../include/quote_822_local.h
 bounce_append_service.o: ../../include/deliver_flock.h
 bounce_append_service.o: bounce_service.h
+bounce_append_service.o: ../../include/bounce_log.h
 bounce_cleanup.o: bounce_cleanup.c
 bounce_cleanup.o: ../../include/sys_defs.h
 bounce_cleanup.o: ../../include/msg.h
@@ -91,59 +93,41 @@ bounce_cleanup.o: ../../include/vbuf.h
 bounce_cleanup.o: ../../include/mail_queue.h
 bounce_cleanup.o: ../../include/vstream.h
 bounce_cleanup.o: bounce_service.h
+bounce_cleanup.o: ../../include/bounce_log.h
 bounce_notify_service.o: bounce_notify_service.c
 bounce_notify_service.o: ../../include/sys_defs.h
 bounce_notify_service.o: ../../include/msg.h
-bounce_notify_service.o: ../../include/vstring.h
-bounce_notify_service.o: ../../include/vbuf.h
 bounce_notify_service.o: ../../include/vstream.h
-bounce_notify_service.o: ../../include/vstring_vstream.h
-bounce_notify_service.o: ../../include/mymalloc.h
-bounce_notify_service.o: ../../include/stringops.h
-bounce_notify_service.o: ../../include/events.h
-bounce_notify_service.o: ../../include/line_wrap.h
+bounce_notify_service.o: ../../include/vbuf.h
 bounce_notify_service.o: ../../include/name_mask.h
-bounce_notify_service.o: ../../include/mail_queue.h
-bounce_notify_service.o: ../../include/mail_proto.h
-bounce_notify_service.o: ../../include/iostuff.h
-bounce_notify_service.o: ../../include/quote_822_local.h
 bounce_notify_service.o: ../../include/mail_params.h
-bounce_notify_service.o: ../../include/canon_addr.h
-bounce_notify_service.o: ../../include/is_header.h
-bounce_notify_service.o: ../../include/record.h
-bounce_notify_service.o: ../../include/rec_type.h
-bounce_notify_service.o: ../../include/mail_conf.h
 bounce_notify_service.o: ../../include/post_mail.h
 bounce_notify_service.o: ../../include/cleanup_user.h
 bounce_notify_service.o: ../../include/mail_addr.h
-bounce_notify_service.o: ../../include/mark_corrupt.h
 bounce_notify_service.o: ../../include/mail_error.h
 bounce_notify_service.o: bounce_service.h
-bounce_recip_service.o: bounce_recip_service.c
-bounce_recip_service.o: ../../include/sys_defs.h
-bounce_recip_service.o: ../../include/msg.h
-bounce_recip_service.o: ../../include/vstring.h
-bounce_recip_service.o: ../../include/vbuf.h
-bounce_recip_service.o: ../../include/vstream.h
-bounce_recip_service.o: ../../include/vstring_vstream.h
-bounce_recip_service.o: ../../include/mymalloc.h
-bounce_recip_service.o: ../../include/stringops.h
-bounce_recip_service.o: ../../include/events.h
-bounce_recip_service.o: ../../include/line_wrap.h
-bounce_recip_service.o: ../../include/name_mask.h
-bounce_recip_service.o: ../../include/mail_queue.h
-bounce_recip_service.o: ../../include/mail_proto.h
-bounce_recip_service.o: ../../include/iostuff.h
-bounce_recip_service.o: ../../include/quote_822_local.h
-bounce_recip_service.o: ../../include/mail_params.h
-bounce_recip_service.o: ../../include/canon_addr.h
-bounce_recip_service.o: ../../include/is_header.h
-bounce_recip_service.o: ../../include/record.h
-bounce_recip_service.o: ../../include/rec_type.h
-bounce_recip_service.o: ../../include/mail_conf.h
-bounce_recip_service.o: ../../include/post_mail.h
-bounce_recip_service.o: ../../include/cleanup_user.h
-bounce_recip_service.o: ../../include/mail_addr.h
-bounce_recip_service.o: ../../include/mark_corrupt.h
-bounce_recip_service.o: ../../include/mail_error.h
-bounce_recip_service.o: bounce_service.h
+bounce_notify_service.o: ../../include/vstring.h
+bounce_notify_service.o: ../../include/bounce_log.h
+bounce_notify_util.o: bounce_notify_util.c
+bounce_notify_util.o: ../../include/sys_defs.h
+bounce_notify_util.o: ../../include/msg.h
+bounce_notify_util.o: ../../include/mymalloc.h
+bounce_notify_util.o: ../../include/events.h
+bounce_notify_util.o: ../../include/vstring.h
+bounce_notify_util.o: ../../include/vbuf.h
+bounce_notify_util.o: ../../include/vstream.h
+bounce_notify_util.o: ../../include/line_wrap.h
+bounce_notify_util.o: ../../include/mail_queue.h
+bounce_notify_util.o: ../../include/quote_822_local.h
+bounce_notify_util.o: ../../include/mail_params.h
+bounce_notify_util.o: ../../include/is_header.h
+bounce_notify_util.o: ../../include/record.h
+bounce_notify_util.o: ../../include/rec_type.h
+bounce_notify_util.o: ../../include/post_mail.h
+bounce_notify_util.o: ../../include/cleanup_user.h
+bounce_notify_util.o: ../../include/mail_addr.h
+bounce_notify_util.o: ../../include/mail_error.h
+bounce_notify_util.o: ../../include/name_mask.h
+bounce_notify_util.o: ../../include/bounce_log.h
+bounce_notify_util.o: ../../include/mail_date.h
+bounce_notify_util.o: bounce_service.h
index 616527fbdf671f5e56d0f3f8f3a386c42fb6cdc5..8ee090d5526e001ac629b75647845624c1d21331 100644 (file)
@@ -21,8 +21,6 @@
 /*     Post a bounce message, with a copy of a log file and of the
 /*     corresponding message. When the bounce is posted successfully,
 /*     the log file is deleted.
-/* .IP \(bu
-/*     Post a bounce message without accessing a per-message log file.
 /* .PP
 /*     The software does a best effort to notify the sender that there
 /*     was a problem. A notification is sent even when the log file
@@ -34,6 +32,7 @@
 /*     themselves, and that depend on retry logic in their own client.
 /* STANDARDS
 /*     RFC 822 (ARPA Internet Text Messages)
+/*     RFC 1894 (Delivery Status Notifications)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /* BUGS
@@ -203,41 +202,6 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
                                  STR(queue_id), STR(sender), flush));
 }
 
-/* bounce_recip_proto - bounce_recip server protocol */
-
-static int bounce_recip_proto(char *service_name, VSTREAM *client, int flush)
-{
-    int     flags;
-
-    /*
-     * Read and validate the client request.
-     */
-    if (mail_command_read(client, "%d %s %s %s %s %s",
-                         &flags, queue_name, queue_id,
-                         sender, recipient, why) != 6) {
-       msg_warn("malformed request");
-       return (-1);
-    }
-    if (mail_queue_name_ok(STR(queue_name)) == 0) {
-       msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
-       return (-1);
-    }
-    if (mail_queue_id_ok(STR(queue_id)) == 0) {
-       msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
-       return (-1);
-    }
-    if (msg_verbose)
-       msg_info("bounce_recip_proto: service=%s queue=%s id=%s sender=%s recip=%s why=%s",
-                service_name, STR(queue_name), STR(queue_id),
-                STR(sender), STR(recipient), STR(why));
-
-    /*
-     * Execute the request.
-     */
-    return (bounce_recip_service(service_name, STR(queue_name), STR(queue_id),
-                            STR(sender), STR(recipient), STR(why), flush));
-}
-
 /* bounce_service - parse bounce command type and delegate */
 
 static void bounce_service(VSTREAM *client, char *service_name, char **argv)
@@ -270,8 +234,6 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
        status = bounce_notify_proto(service_name, client, JUST_WARN);
     } else if (command == BOUNCE_CMD_APPEND) {
        status = bounce_append_proto(service_name, client);
-    } else if (command == BOUNCE_CMD_RECIP) {
-       status = bounce_recip_proto(service_name, client, REALLY_BOUNCE);
     } else {
        msg_warn("unknown command: %d", command);
        status = -1;
index 78bcfa1a9573dd3c22a990c1dbecc6a3e9a2df41..4f668841d64761cf709dbf0730d5b5e5b88d8d40 100644 (file)
 /* Utility library. */
 
 #include <msg.h>
-#include <vstring.h>
 #include <vstream.h>
-#include <vstring_vstream.h>
-#include <mymalloc.h>
-#include <stringops.h>
-#include <events.h>
-#include <line_wrap.h>
 #include <name_mask.h>
 
 /* Global library. */
 
-#include <mail_queue.h>
-#include <mail_proto.h>
-#include <quote_822_local.h>
 #include <mail_params.h>
-#include <canon_addr.h>
-#include <is_header.h>
-#include <record.h>
-#include <rec_type.h>
-#include <mail_conf.h>
+#include <mail_queue.h>
 #include <post_mail.h>
 #include <mail_addr.h>
-#include <mark_corrupt.h>
 #include <mail_error.h>
 
 /* Application-specific. */
 
 #define STR vstring_str
 
-/* bounce_header - generate bounce message header */
-
-static int bounce_header(VSTREAM *bounce, VSTRING *buf, const char *dest,
-                                const char *boundary, int flush)
-{
-
-    /*
-     * Print a minimal bounce header. The cleanup service will add other
-     * headers and will make all addresses fully qualified.
-     */
-#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
-
-    post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
-                     MAIL_ADDR_MAIL_DAEMON);
-
-    if (flush) {
-       post_mail_fputs(bounce, dest == var_bounce_rcpt
-                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
-                       "Subject: Postmaster Copy: Undelivered Mail" :
-                       "Subject: Undelivered Mail Returned to Sender");
-    } else {
-       post_mail_fputs(bounce, dest == var_bounce_rcpt
-                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
-                       "Subject: Postmaster Warning: Delayed Mail" :
-                       "Subject: Delayed Mail (still being retried)");
-    }
-    post_mail_fprintf(bounce, "To: %s", STR(quote_822_local(buf, dest)));
-
-    /*
-     * MIME header.
-     */
-    post_mail_fprintf(bounce, "MIME-Version: 1.0");
-#ifdef DSN
-    post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
-                     "multipart/report", "delivery-status");
-#else
-    post_mail_fprintf(bounce, "Content-Type: multipart/mixed;");
-#endif
-    post_mail_fprintf(bounce, "\tboundary=\"%s\"", boundary);
-    post_mail_fputs(bounce, "");
-    post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
-
-    /*
-     * More MIME header.
-     */
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
-    post_mail_fprintf(bounce, "Content-Type: %s", "text/plain");
-    post_mail_fputs(bounce, "");
-
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_boilerplate - generate boiler-plate text */
-
-static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf,
-                                     const char *boundary, int flush)
-{
-
-    /*
-     * Print the message body with the problem report. XXX For now, we use a
-     * fixed bounce template. We could use a site-specific parametrized
-     * template with ${name} macros and we could do wonderful things such as
-     * word wrapping to make the text look nicer. No matter how hard we would
-     * try, receiving bounced mail will always suck.
-     */
-    post_mail_fprintf(bounce, "This is the %s program at host %s.",
-                     var_mail_name, var_myhostname);
-    post_mail_fputs(bounce, "");
-    if (flush) {
-       post_mail_fputs(bounce,
-              "I'm sorry to have to inform you that the message returned");
-       post_mail_fputs(bounce,
-              "below could not be delivered to one or more destinations.");
-    } else {
-       post_mail_fputs(bounce,
-                       "####################################################################");
-       post_mail_fputs(bounce,
-                       "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
-       post_mail_fputs(bounce,
-                       "####################################################################");
-       post_mail_fputs(bounce, "");
-       post_mail_fprintf(bounce,
-                       "Your message could not be delivered for %d hours.",
-                         var_delay_warn_time);
-       post_mail_fprintf(bounce,
-                         "It will be retried until it is %d days old.",
-                         var_max_queue_time);
-    }
-
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce,
-                     "For further assistance, please contact <%s>",
-                     STR(canon_addr_external(buf, MAIL_ADDR_POSTMASTER)));
-    if (flush) {
-       post_mail_fputs(bounce, "");
-       post_mail_fprintf(bounce,
-              "If you do so, please include this problem report. You can");
-       post_mail_fprintf(bounce,
-                  "delete your own text from the message returned below.");
-    }
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
-    post_mail_fputs(bounce, "");
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_print - line_wrap callback */
-
-static void bounce_print(const char *str, int len, int indent, char *context)
-{
-    VSTREAM *bounce = (VSTREAM *) context;
-
-    post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
-}
-
-/* bounce_diagnostics - send bounce log report */
-
-static int bounce_diagnostics(char *service, VSTREAM *bounce, VSTRING *buf,
-                                     char *queue_id, const char *boundary)
-{
-    VSTREAM *log;
-
-    /*
-     * MIME header.
-     */
-#ifdef DSN
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Delivery error report");
-    post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
-    post_mail_fputs(bounce, "");
-#endif
-
-    /*
-     * If the bounce log cannot be found, do not raise a fatal run-time
-     * error. There is nothing we can do about the error, and all we are
-     * doing is to inform the sender of a delivery problem, Bouncing a
-     * message does not have to be a perfect job. But if the system IS
-     * running out of resources, raise a fatal run-time error and force a
-     * backoff.
-     */
-    if ((log = mail_queue_open(service, queue_id, O_RDONLY, 0)) == 0) {
-       if (errno != ENOENT)
-           msg_fatal("open %s %s: %m", service, queue_id);
-       post_mail_fputs(bounce, "\t--- Delivery error report unavailable ---");
-       post_mail_fputs(bounce, "");
-    }
-
-    /*
-     * Append a copy of the delivery error log. Again, we're doing a best
-     * effort, so there is no point raising a fatal run-time error in case of
-     * a logfile read error. Wrap long lines, filter non-printable
-     * characters, and prepend one blank, so this data can safely be piped
-     * into other programs.
-     */
-    else {
-
-#define LENGTH 79
-#define INDENT 4
-       while (vstream_ferror(bounce) == 0 && vstring_fgets_nonl(buf, log)) {
-           printable(STR(buf), '_');
-           line_wrap(STR(buf), LENGTH, INDENT, bounce_print, (char *) bounce);
-           if (vstream_ferror(bounce) != 0)
-               break;
-       }
-       if (vstream_fclose(log))
-           msg_warn("read bounce log %s: %m", queue_id);
-    }
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_original - send a copy of the original to the victim */
-
-static int bounce_original(char *service, VSTREAM *bounce, VSTRING *buf,
-                                  char *queue_name, char *queue_id,
-                                  const char *boundary, int headers_only)
-{
-    int     status = 0;
-    VSTREAM *src;
-    int     rec_type;
-    int     bounce_length;
-
-    /*
-     * MIME headers.
-     */
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Undelivered Message");
-    post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
-                     "text/rfc822-headers" : "message/rfc822");
-    post_mail_fputs(bounce, "");
-
-    /*
-     * If the original message cannot be found, do not raise a run-time
-     * error. There is nothing we can do about the error, and all we are
-     * doing is to inform the sender of a delivery problem. Bouncing a
-     * message does not have to be a perfect job. But if the system IS
-     * running out of resources, raise a fatal run-time error and force a
-     * backoff.
-     */
-    if ((src = mail_queue_open(queue_name, queue_id, O_RDONLY, 0)) == 0) {
-       if (errno != ENOENT)
-           msg_fatal("open %s %s: %m", service, queue_id);
-       post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
-       post_mail_fputs(bounce, "");
-       return (vstream_ferror(bounce));
-    }
-
-    /*
-     * Skip over the original message envelope records. If the envelope is
-     * corrupted just send whatever we can (remember this is a best effort,
-     * it does not have to be perfect).
-     */
-    while ((rec_type = rec_get(src, buf, 0)) > 0)
-       if (rec_type == REC_TYPE_MESG)
-           break;
-
-    /*
-     * Copy the original message contents. Limit the amount of bounced text
-     * so there is a better chance of the bounce making it back. We're doing
-     * raw record output here so that we don't throw away binary transparency
-     * yet.
-     */
-#define IS_HEADER(s) (ISSPACE(*(s)) || is_header(s))
-
-    bounce_length = 0;
-    while (status == 0 && (rec_type = rec_get(src, buf, 0)) > 0) {
-       if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
-           break;
-       if (headers_only && !IS_HEADER(vstring_str(buf)))
-           break;
-       if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) {
-           bounce_length += VSTRING_LEN(buf);
-           status = (REC_PUT_BUF(bounce, rec_type, buf) != rec_type);
-       }
-    }
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s--", boundary);
-    if (headers_only == 0 && rec_type != REC_TYPE_XTRA)
-       status |= mark_corrupt(src);
-    if (vstream_fclose(src))
-       msg_warn("read message file %s %s: %m", queue_name, queue_id);
-    return (status);
-}
-
 /* bounce_notify_service - send a bounce */
 
 int     bounce_notify_service(char *service, char *queue_name,
                                 char *queue_id, char *recipient, int flush)
 {
-    VSTRING *buf = vstring_alloc(100);
+    BOUNCE_INFO *bounce_info;
     int     bounce_status = 1;
     int     postmaster_status = 1;
     VSTREAM *bounce;
     int     notify_mask = name_mask(mail_error_masks, var_notify_classes);
-    VSTRING *boundary = vstring_alloc(100);
     char   *postmaster;
 
     /*
-     * Unique string for multi-part message boundaries.
+     * Initialize. Open queue file, bounce log, etc.
      */
-    vstring_sprintf(boundary, "%s.%ld/%s",
-                   queue_id, (long) event_time(), var_myhostname);
+    bounce_info = bounce_mail_init(service, queue_name, queue_id, flush);
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_CLEANUP_FLAGS     0
@@ -382,7 +119,7 @@ int     bounce_notify_service(char *service, char *queue_name,
      */
     if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
        msg_warn("%s: undeliverable postmaster notification discarded",
-                 queue_id);
+                queue_id);
        bounce_status = 0;
     }
 
@@ -409,13 +146,12 @@ int     bounce_notify_service(char *service, char *queue_name,
                 * reason for the bounce, and the headers of the original
                 * message. Don't bother sending the boiler-plate text.
                 */
-               if (!bounce_header(bounce, buf, postmaster,
-                                  STR(boundary), flush)
-                   && bounce_diagnostics(service, bounce, buf, queue_id,
-                                         STR(boundary)) == 0)
-                   bounce_original(service, bounce, buf, queue_name, queue_id,
-                                   STR(boundary),
-                                   flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+               if (!bounce_header(bounce, bounce_info, postmaster)
+                   && bounce_diagnostic_log(bounce, bounce_info) == 0
+                   && bounce_header_dsn(bounce, bounce_info) == 0
+                   && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+                   bounce_original(bounce, bounce_info, flush ?
+                                   BOUNCE_ALL : BOUNCE_HEADERS);
                bounce_status = post_mail_fclose(bounce);
            }
        }
@@ -426,21 +162,21 @@ int     bounce_notify_service(char *service, char *queue_name,
      */
     else {
        if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
-                                            NULL_CLEANUP_FLAGS,
-                                            "BOUNCE")) != 0) {
+                                               NULL_CLEANUP_FLAGS,
+                                               "BOUNCE")) != 0) {
 
            /*
             * Send the bounce message header, some boilerplate text that
             * pretends that we are a polite mail system, the text with
             * reason for the bounce, and a copy of the original message.
             */
-           if (bounce_header(bounce, buf, recipient, STR(boundary), flush) == 0
-               && bounce_boilerplate(bounce, buf, STR(boundary), flush) == 0
-               && bounce_diagnostics(service, bounce, buf, queue_id,
-                                     STR(boundary)) == 0)
-               bounce_original(service, bounce, buf, queue_name, queue_id,
-                               STR(boundary),
-                               flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+           if (bounce_header(bounce, bounce_info, recipient) == 0
+               && bounce_boilerplate(bounce, bounce_info) == 0
+               && bounce_diagnostic_log(bounce, bounce_info) == 0
+               && bounce_header_dsn(bounce, bounce_info) == 0
+               && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+               bounce_original(bounce, bounce_info, flush ?
+                               BOUNCE_ALL : BOUNCE_HEADERS);
            bounce_status = post_mail_fclose(bounce);
        }
 
@@ -468,12 +204,11 @@ int     bounce_notify_service(char *service, char *queue_name,
                                                 postmaster,
                                                 NULL_CLEANUP_FLAGS,
                                                 "BOUNCE")) != 0) {
-               if (!bounce_header(bounce, buf, postmaster,
-                                  STR(boundary), flush)
-                   && bounce_diagnostics(service, bounce, buf,
-                                         queue_id, STR(boundary)) == 0)
-                   bounce_original(service, bounce, buf, queue_name, queue_id,
-                                   STR(boundary), BOUNCE_HEADERS);
+               if (bounce_header(bounce, bounce_info, postmaster) == 0
+                   && bounce_diagnostic_log(bounce, bounce_info) == 0
+                   && bounce_header_dsn(bounce, bounce_info) == 0
+                   && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+                   bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
                postmaster_status = post_mail_fclose(bounce);
            }
            if (postmaster_status)
@@ -494,8 +229,7 @@ int     bounce_notify_service(char *service, char *queue_name,
     /*
      * Cleanup.
      */
-    vstring_free(buf);
-    vstring_free(boundary);
+    bounce_mail_free(bounce_info);
 
     return (bounce_status);
 }
diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c
new file mode 100644 (file)
index 0000000..921dc28
--- /dev/null
@@ -0,0 +1,561 @@
+/*++
+/* NAME
+/*     bounce_notify_util 3
+/* SUMMARY
+/*     send non-delivery report to sender, server side
+/* SYNOPSIS
+/*     #include "bounce_service.h"
+/*
+/*     typedef struct {
+/* .in +4
+/*             /* All private members... */
+/* .in -4
+/*     } BOUNCE_INFO;
+/*
+/*     BOUNCE_INFO *bounce_mail_init(service, queue_name, queue_id, flush)
+/*     const char *service;
+/*     const char *queue_name;
+/*     const char *queue_id;
+/*     int     flush;
+/*
+/*     void    bounce_mail_free(bounce_info)
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_header(fp, bounce_info, recipient)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*     const char *recipient;
+/*
+/*     int     bounce_boilerplate(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_recipient_log(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_diagnostic_log(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_header_dsn(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_recipient_dsn(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_diagnostic_dsn(fp, bounce_info)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*
+/*     int     bounce_original(fp, bounce_info, headers_only)
+/*     VSTREAM *fp;
+/*     BOUNCE_INFO *bounce_info;
+/*     int     headers_only;
+/* DESCRIPTION
+/*     This module implements the grunt work of sending a non-delivery
+/*     notification. A bounce is sent in a form that satisfies RFC 1894
+/*     (delivery status notifications).
+/*
+/*     bounce_mail_init() bundles up its argument and attempts to
+/*     open the corresponding logfile and message file. A BOUNCE_INFO
+/*     structure contains all the necessary information about an
+/*     undeliverable message.
+/*
+/*     bounce_mail_free() releases memory allocated by bounce_mail_init()
+/*     and closes any files opened by bounce_mail_init().
+/*
+/*     bounce_header() produces a standard mail header with the specified
+/*     recipient and starts a text/plain message segment for the
+/*     human-readable problem description.
+/*
+/*     bounce_boilerplate() produces the standard "sorry" text that
+/*     creates the illusion that mail systems are civilized.
+/*
+/*     bounce_recipient_log() sends a human-readable representation of
+/*     logfile information for one recipient, with the recipient address
+/*     and with the text why the recipient was undeliverable.
+/*
+/*     bounce_diagnostic_log() sends a human-readable representation of
+/*     logfile information for all undeliverable recipients. This routine
+/*     will become obsolete when individual recipients of the same message
+/*     can have different sender addresses to bounce to.
+/*
+/*     bounce_header_dsn() starts a message/delivery-status message
+/*     segment and sends the machine-readable information that identifies
+/*     the reporting MTA.
+/*
+/*     bounce_recipient_dsn() sends a machine-readable representation of
+/*     logfile information for one recipient, with the recipient address
+/*     and with the text why the recipient was undeliverable.
+/*
+/*     bounce_diagnostic_dsn() sends a machine-readable representation of
+/*     logfile information for all undeliverable recipients. This routine
+/*     will become obsolete when individual recipients of the same message
+/*     can have different sender addresses to bounce to.
+/*
+/*     bounce_original() starts a message/rfc822 or headers/rfc822
+/*     message segment and sends the original message, either full or
+/*     message headers only.
+/* DIAGNOSTICS
+/*     Fatal error: error opening existing file. Warnings: corrupt
+/*     message file. A corrupt message is saved to the "corrupt"
+/*     queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/*     bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <events.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <line_wrap.h>
+
+/* Global library. */
+
+#include <mail_queue.h>
+#include <quote_822_local.h>
+#include <mail_params.h>
+#include <is_header.h>
+#include <record.h>
+#include <rec_type.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mail_error.h>
+#include <bounce_log.h>
+#include <mail_date.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_mail_init - initialize */
+
+BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name,
+                                     const char *queue_id, int flush)
+{
+    BOUNCE_INFO *bounce_info;
+    int     rec_type;
+
+    /*
+     * Bundle up a bunch of parameters and initialize information. that will
+     * be discovered on the fly.
+     */
+    bounce_info = (BOUNCE_INFO *) mymalloc(sizeof(*bounce_info));
+    bounce_info->service = service;
+    bounce_info->queue_name = queue_name;
+    bounce_info->queue_id = queue_id;
+    bounce_info->flush = flush;
+    bounce_info->buf = vstring_alloc(100);
+    bounce_info->arrival_time = 0;
+    bounce_info->orig_offs = 0;
+
+    /*
+     * Compute a supposedly unique boundary string. This assumes that a queue
+     * ID and a hostname contain acceptable characters for a boundary string,
+     * but the assumption is not verified.
+     */
+    vstring_sprintf(bounce_info->buf, "%s.%lu/%s",
+                   queue_id, (unsigned long) event_time(), var_myhostname);
+    bounce_info->mime_boundary = mystrdup(STR(bounce_info->buf));
+
+    /*
+     * If the bounce log cannot be found, do not raise a fatal run-time
+     * error. There is nothing we can do about the error, and all we are
+     * doing is to inform the sender of a delivery problem, Bouncing a
+     * message does not have to be a perfect job. But if the system IS
+     * running out of resources, raise a fatal run-time error and force a
+     * backoff.
+     */
+    if ((bounce_info->log_handle = bounce_log_open(bounce_info->service,
+                                                  bounce_info->queue_id,
+                                                  O_RDONLY, 0)) == 0
+       && errno != ENOENT)
+       msg_fatal("open %s %s: %m", bounce_info->service,
+                 bounce_info->queue_id);
+
+    /*
+     * If the original message cannot be found, do not raise a run-time
+     * error. There is nothing we can do about the error, and all we are
+     * doing is to inform the sender of a delivery problem. Bouncing a
+     * message does not have to be a perfect job. But if the system IS
+     * running out of resources, raise a fatal run-time error and force a
+     * backoff.
+     */
+    if ((bounce_info->orig_fp = mail_queue_open(queue_name, queue_id,
+                                               O_RDONLY, 0)) == 0
+       && errno != ENOENT)
+       msg_fatal("open %s %s: %m", service, queue_id);
+
+    /*
+     * Skip over the original message envelope records. If the envelope is
+     * corrupted just send whatever we can (remember this is a best effort,
+     * it does not have to be perfect).
+     */
+    while ((rec_type = rec_get(bounce_info->orig_fp,
+                              bounce_info->buf, 0)) > 0) {
+       if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) {
+           if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
+               bounce_info->arrival_time = 0;
+       } else if (rec_type == REC_TYPE_MESG) {
+           bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
+           break;
+       }
+    }
+    return (bounce_info);
+}
+
+/* bounce_mail_free - undo bounce_mail_init */
+
+void    bounce_mail_free(BOUNCE_INFO *bounce_info)
+{
+    if (bounce_info->log_handle && bounce_log_close(bounce_info->log_handle))
+       msg_warn("%s: read bounce log %s: %m",
+                bounce_info->queue_id, bounce_info->queue_id);
+    if (bounce_info->orig_fp && vstream_fclose(bounce_info->orig_fp))
+       msg_warn("%s: read message file %s %s: %m",
+                bounce_info->queue_id, bounce_info->queue_name,
+                bounce_info->queue_id);
+    vstring_free(bounce_info->buf);
+    myfree((char *) bounce_info->mime_boundary);
+    myfree((char *) bounce_info);
+}
+
+/* bounce_header - generate bounce message header */
+
+int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
+                             const char *dest)
+{
+
+    /*
+     * Print a minimal bounce header. The cleanup service will add other
+     * headers and will make all addresses fully qualified.
+     */
+#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
+
+    post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
+                     MAIL_ADDR_MAIL_DAEMON);
+
+    /*
+     * Non-delivery subject line.
+     */
+    if (bounce_info->flush) {
+       post_mail_fputs(bounce, dest == var_bounce_rcpt
+                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
+                       "Subject: Postmaster Copy: Undelivered Mail" :
+                       "Subject: Undelivered Mail Returned to Sender");
+    }
+
+    /*
+     * Delayed mail subject line.
+     */
+    else {
+       post_mail_fputs(bounce, dest == var_bounce_rcpt
+                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
+                       "Subject: Postmaster Warning: Delayed Mail" :
+                       "Subject: Delayed Mail (still being retried)");
+    }
+    post_mail_fprintf(bounce, "To: %s",
+                     STR(quote_822_local(bounce_info->buf, dest)));
+
+    /*
+     * MIME header.
+     */
+    post_mail_fprintf(bounce, "MIME-Version: 1.0");
+    post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
+                     "multipart/report", "delivery-status");
+    post_mail_fprintf(bounce, "\tboundary=\"%s\"", bounce_info->mime_boundary);
+    post_mail_fputs(bounce, "");
+    post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
+
+    /*
+     * MIME header.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
+    post_mail_fprintf(bounce, "Content-Type: %s", "text/plain");
+    post_mail_fputs(bounce, "");
+
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_boilerplate - generate boiler-plate text */
+
+int     bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+
+    /*
+     * Print the message body with the problem report. XXX For now, we use a
+     * fixed bounce template. We could use a site-specific parametrized
+     * template with ${name} macros and we could do wonderful things such as
+     * word wrapping to make the text look nicer. No matter how hard we would
+     * try, receiving bounced mail will always suck.
+     */
+    post_mail_fprintf(bounce, "This is the %s program at host %s.",
+                     var_mail_name, var_myhostname);
+    post_mail_fputs(bounce, "");
+    if (bounce_info->flush) {
+       post_mail_fputs(bounce,
+              "I'm sorry to have to inform you that the message returned");
+       post_mail_fputs(bounce,
+              "below could not be delivered to one or more destinations.");
+    } else {
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce,
+                       "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+                       "Your message could not be delivered for %d hours.",
+                         var_delay_warn_time);
+       post_mail_fprintf(bounce,
+                         "It will be retried until it is %d days old.",
+                         var_max_queue_time);
+    }
+
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce,
+                     "For further assistance, please send mail to <%s>",
+                     MAIL_ADDR_POSTMASTER);
+    if (bounce_info->flush) {
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+              "If you do so, please include this problem report. You can");
+       post_mail_fprintf(bounce,
+                  "delete your own text from the message returned below.");
+    }
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_print - line_wrap callback */
+
+static void bounce_print(const char *str, int len, int indent, char *context)
+{
+    VSTREAM *bounce = (VSTREAM *) context;
+
+    post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
+}
+
+/* bounce_print_wrap - print and wrap a line */
+
+static void bounce_print_wrap(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
+                                     const char *format,...)
+{
+    va_list ap;
+
+#define LENGTH 79
+#define INDENT 4
+
+    va_start(ap, format);
+    vstring_vsprintf(bounce_info->buf, format, ap);
+    va_end(ap);
+    line_wrap(STR(bounce_info->buf), LENGTH, INDENT,
+             bounce_print, (char *) bounce);
+}
+
+/* bounce_recipient_log - send one bounce log report entry */
+
+int     bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+
+    /*
+     * Mask control and non-ASCII characters (done in bounce_log_read()),
+     * wrap long lines and prepend one blank, so this data can safely be
+     * piped into other programs. Sort of like TCP Wrapper's safe_finger
+     * program.
+     */
+    post_mail_fputs(bounce, "");
+    bounce_print_wrap(bounce, bounce_info, "<%s>: %s",
+        bounce_info->log_handle->recipient, bounce_info->log_handle->text);
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_diagnostic_log - send bounce log report */
+
+int     bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+
+    /*
+     * Append a copy of the delivery error log. We're doing a best effort, so
+     * there is no point raising a fatal run-time error in case of a logfile
+     * read error.
+     */
+    if (bounce_info->log_handle == 0
+       || bounce_log_rewind(bounce_info->log_handle)) {
+       post_mail_fputs(bounce, "\t--- Delivery error report unavailable ---");
+    } else {
+       while (bounce_log_read(bounce_info->log_handle) != 0)
+           if (bounce_recipient_log(bounce, bounce_info) != 0)
+               break;
+    }
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_header_dsn - send per-MTA bounce DSN records */
+
+int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+
+    /*
+     * MIME header.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s",
+                     "Delivery error report");
+    post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
+
+    /*
+     * According to RFC 1894: The body of a message/delivery-status consists
+     * of one or more "fields" formatted according to the ABNF of RFC 822
+     * header "fields" (see [6]).  The per-message fields appear first,
+     * followed by a blank line.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "Reporting-MTA: dns; %s", var_myhostname);
+#if 0
+    post_mail_fprintf(bounce, "Received-From-MTA: dns; %s", "whatever");
+#endif
+    if (bounce_info->arrival_time > 0)
+       post_mail_fprintf(bounce, "Arrival-Date: %s",
+                         mail_date(bounce_info->arrival_time));
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_recipient_dsn - send per-recipient DSN records */
+
+int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+    post_mail_fputs(bounce, "");
+#if 0
+    post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s", "whatever");
+#endif
+    post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s",
+                     bounce_info->log_handle->recipient);
+    post_mail_fprintf(bounce, "Action: %s", bounce_info->flush ?
+                     "failed" : "delayed");
+    post_mail_fprintf(bounce, "Status: %s", bounce_info->log_handle->status);
+    bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-Postfix; %s",
+                     bounce_info->log_handle->text);
+#if 0
+    post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
+                     bounce_info->log_handle->log_time);
+#endif
+    if (bounce_info->flush == 0)
+       post_mail_fprintf(bounce, "Will-Retry-Until: %s",
+        mail_date(bounce_info->arrival_time + 86400 * var_max_queue_time));
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_diagnostic_dsn - send bounce log report, machine readable form */
+
+int     bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
+{
+
+    /*
+     * Append a copy of the delivery error log. We're doing a best effort, so
+     * there is no point raising a fatal run-time error in case of a logfile
+     * read error.
+     */
+    if (bounce_info->log_handle != 0
+       && bounce_log_rewind(bounce_info->log_handle) == 0) {
+       while (bounce_log_read(bounce_info->log_handle) != 0)
+           if (bounce_recipient_dsn(bounce, bounce_info) != 0)
+               break;
+    }
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_original - send a copy of the original to the victim */
+
+int     bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
+                               int headers_only)
+{
+    int     status = 0;
+    int     rec_type = 0;
+    int     bounce_length;
+
+    /*
+     * MIME headers.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s", headers_only ?
+                     "Undelivered Message Headers" : "Undelivered Message");
+    post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
+                     "text/rfc822-headers" : "message/rfc822");
+    post_mail_fputs(bounce, "");
+
+    /*
+     * Send place holder if original is unavailable.
+     */
+    if (bounce_info->orig_offs == 0 || vstream_fseek(bounce_info->orig_fp,
+                                   bounce_info->orig_offs, SEEK_SET) < 0) {
+       post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
+       return (vstream_ferror(bounce));
+    }
+
+    /*
+     * Copy the original message contents. Limit the amount of bounced text
+     * so there is a better chance of the bounce making it back. We're doing
+     * raw record output here so that we don't throw away binary transparency
+     * yet.
+     */
+#define IS_HEADER(s) (ISSPACE(*(s)) || is_header(s))
+
+    bounce_length = 0;
+    while (status == 0 && (rec_type = rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0) {
+       if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
+           break;
+       if (headers_only && !IS_HEADER(vstring_str(bounce_info->buf)))
+           break;
+       if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) {
+           bounce_length += VSTRING_LEN(bounce_info->buf) + 2;
+           status = (REC_PUT_BUF(bounce, rec_type, bounce_info->buf) != rec_type);
+       }
+    }
+
+    /*
+     * Final MIME headers. These require -- at the end of the boundary
+     * string.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s--", bounce_info->mime_boundary);
+
+    return (status);
+}
diff --git a/postfix/src/bounce/bounce_recip_service.c b/postfix/src/bounce/bounce_recip_service.c
deleted file mode 100644 (file)
index 2ff9cc0..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*++
-/* NAME
-/*     bounce_recip_service 3
-/* SUMMARY
-/*     send non-delivery report to sender, server side
-/* SYNOPSIS
-/*     #include "bounce_service.h"
-/*
-/*     int     bounce_recip_service(queue_name, queue_id, sender,
-/*                                     bounced_addr, why, flush)
-/*     char    *queue_name;
-/*     char    *queue_id;
-/*     char    *sender;
-/*     char    *recipient;
-/*     char    *why;
-/*     int     flush;
-/* DESCRIPTION
-/*     This module implements the server side of the bounce_recip()
-/*     (send bounce message) request. If flush is zero, a warning is
-/*     sent instead of a bounce.
-/*
-/*     When a message bounces, a full copy is sent to the originator,
-/*     and an optional  copy of the diagnostics with message headers is
-/*     sent to the postmaster.  The result is non-zero when the operation
-/*     should be tried again.
-/*
-/*     When a bounce is sent, the sender address is the empty
-/*     address.  When a bounce bounces, an optional double bounce
-/*     with the entire undeliverable mail is sent to the postmaster,
-/*     with as sender address the double bounce address.
-/* DIAGNOSTICS
-/*     Fatal error: error opening existing file. Warnings: corrupt
-/*     message file. A corrupt message is saved to the "corrupt"
-/*     queue for further inspection.
-/* BUGS
-/* SEE ALSO
-/*     bounce(3) basic bounce service client interface
-/* LICENSE
-/* .ad
-/* .fi
-/*     The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/*     Wietse Venema
-/*     IBM T.J. Watson Research
-/*     P.O. Box 704
-/*     Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <mymalloc.h>
-#include <stringops.h>
-#include <events.h>
-#include <line_wrap.h>
-#include <name_mask.h>
-
-/* Global library. */
-
-#include <mail_queue.h>
-#include <mail_proto.h>
-#include <quote_822_local.h>
-#include <mail_params.h>
-#include <canon_addr.h>
-#include <is_header.h>
-#include <record.h>
-#include <rec_type.h>
-#include <mail_conf.h>
-#include <post_mail.h>
-#include <mail_addr.h>
-#include <mark_corrupt.h>
-#include <mail_error.h>
-
-/* Application-specific. */
-
-#include "bounce_service.h"
-
-#define STR vstring_str
-
-/* bounce_header - generate bounce message header */
-
-static int bounce_header(VSTREAM *bounce, VSTRING *buf, const char *dest,
-                                const char *boundary, int flush)
-{
-
-    /*
-     * Print a minimal bounce header. The cleanup service will add other
-     * headers and will make all addresses fully qualified.
-     */
-#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
-
-    post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
-                     MAIL_ADDR_MAIL_DAEMON);
-
-    if (flush) {
-       post_mail_fputs(bounce, dest == var_bounce_rcpt
-                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
-                       "Subject: Postmaster Copy: Undelivered Mail" :
-                       "Subject: Undelivered Mail Returned to Sender");
-    } else {
-       post_mail_fputs(bounce, dest == var_bounce_rcpt
-                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
-                       "Subject: Postmaster Warning: Delayed Mail" :
-                       "Subject: Delayed Mail (still being retried)");
-    }
-    post_mail_fprintf(bounce, "To: %s", STR(quote_822_local(buf, dest)));
-
-    /*
-     * MIME header.
-     */
-    post_mail_fprintf(bounce, "MIME-Version: 1.0");
-#ifdef DSN
-    post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
-                     "multipart/report", "delivery-status");
-#else
-    post_mail_fprintf(bounce, "Content-Type: multipart/mixed;");
-#endif
-    post_mail_fprintf(bounce, "\tboundary=\"%s\"", boundary);
-    post_mail_fputs(bounce, "");
-    post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
-
-    /*
-     * More MIME header.
-     */
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
-    post_mail_fprintf(bounce, "Content-Type: %s", "text/plain");
-    post_mail_fputs(bounce, "");
-
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_boilerplate - generate boiler-plate text */
-
-static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf,
-                                     const char *boundary, int flush)
-{
-
-    /*
-     * Print the message body with the problem report. XXX For now, we use a
-     * fixed bounce template. We could use a site-specific parametrized
-     * template with ${name} macros and we could do wonderful things such as
-     * word wrapping to make the text look nicer. No matter how hard we would
-     * try, receiving bounced mail will always suck.
-     */
-    post_mail_fprintf(bounce, "This is the %s program at host %s.",
-                     var_mail_name, var_myhostname);
-    post_mail_fputs(bounce, "");
-    if (flush) {
-       post_mail_fputs(bounce,
-              "I'm sorry to have to inform you that the message returned");
-       post_mail_fputs(bounce,
-              "below could not be delivered to one or more destinations.");
-    } else {
-       post_mail_fputs(bounce,
-                       "####################################################################");
-       post_mail_fputs(bounce,
-                       "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
-       post_mail_fputs(bounce,
-                       "####################################################################");
-       post_mail_fputs(bounce, "");
-       post_mail_fprintf(bounce,
-                       "Your message could not be delivered for %d hours.",
-                         var_delay_warn_time);
-       post_mail_fprintf(bounce,
-                         "It will be retried until it is %d days old.",
-                         var_max_queue_time);
-    }
-
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce,
-                     "For further assistance, please contact <%s>",
-                     STR(canon_addr_external(buf, MAIL_ADDR_POSTMASTER)));
-    if (flush) {
-       post_mail_fputs(bounce, "");
-       post_mail_fprintf(bounce,
-              "If you do so, please include this problem report. You can");
-       post_mail_fprintf(bounce,
-                  "delete your own text from the message returned below.");
-    }
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
-    post_mail_fputs(bounce, "");
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_print - line_wrap callback */
-
-static void bounce_print(const char *str, int len, int indent, char *context)
-{
-    VSTREAM *bounce = (VSTREAM *) context;
-
-    post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
-}
-
-/* bounce_diagnostics - send bounce log report */
-
-static int bounce_diagnostics(VSTREAM *bounce, const char *boundary,
-                                   const char *unused_recipient, char *why)
-{
-
-    /*
-     * MIME header.
-     */
-#ifdef DSN
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Delivery error report");
-    post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
-    post_mail_fputs(bounce, "");
-#endif
-
-    /*
-     * Append a copy of the delivery error log. Again, we're doing a best
-     * effort, so there is no point raising a fatal run-time error in case of
-     * a logfile read error. Wrap long lines, filter non-printable
-     * characters, and prepend one blank, so this data can safely be piped
-     * into other programs.
-     * 
-     * XXX recipient may be empty.
-     */
-
-#define LENGTH 79
-#define INDENT 4
-    printable(why, '_');
-    line_wrap(why, LENGTH, INDENT, bounce_print, (char *) bounce);
-    return (vstream_ferror(bounce));
-}
-
-/* bounce_original - send a copy of the original to the victim */
-
-static int bounce_original(char *service, VSTREAM *bounce, VSTRING *buf,
-                                  char *queue_name, char *queue_id,
-                                  const char *boundary, int headers_only)
-{
-    int     status = 0;
-    VSTREAM *src;
-    int     rec_type;
-    int     bounce_length;
-
-    /*
-     * MIME headers.
-     */
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s", boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", "Undelivered Message");
-    post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
-                     "text/rfc822-headers" : "message/rfc822");
-    post_mail_fputs(bounce, "");
-
-    /*
-     * If the original message cannot be found, do not raise a run-time
-     * error. There is nothing we can do about the error, and all we are
-     * doing is to inform the sender of a delivery problem. Bouncing a
-     * message does not have to be a perfect job. But if the system IS
-     * running out of resources, raise a fatal run-time error and force a
-     * backoff.
-     */
-    if ((src = mail_queue_open(queue_name, queue_id, O_RDONLY, 0)) == 0) {
-       if (errno != ENOENT)
-           msg_fatal("open %s %s: %m", service, queue_id);
-       post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
-       post_mail_fputs(bounce, "");
-       return (vstream_ferror(bounce));
-    }
-
-    /*
-     * Skip over the original message envelope records. If the envelope is
-     * corrupted just send whatever we can (remember this is a best effort,
-     * it does not have to be perfect).
-     */
-    while ((rec_type = rec_get(src, buf, 0)) > 0)
-       if (rec_type == REC_TYPE_MESG)
-           break;
-
-    /*
-     * Copy the original message contents. Limit the amount of bounced text
-     * so there is a better chance of the bounce making it back. We're doing
-     * raw record output here so that we don't throw away binary transparency
-     * yet.
-     */
-#define IS_HEADER(s) (ISSPACE(*(s)) || is_header(s))
-
-    bounce_length = 0;
-    while (status == 0 && (rec_type = rec_get(src, buf, 0)) > 0) {
-       if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
-           break;
-       if (headers_only && !IS_HEADER(vstring_str(buf)))
-           break;
-       if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) {
-           bounce_length += VSTRING_LEN(buf);
-           status = (REC_PUT_BUF(bounce, rec_type, buf) != rec_type);
-       }
-    }
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "--%s--", boundary);
-    if (headers_only == 0 && rec_type != REC_TYPE_XTRA)
-       status |= mark_corrupt(src);
-    if (vstream_fclose(src))
-       msg_warn("read message file %s %s: %m", queue_name, queue_id);
-    return (status);
-}
-
-/* bounce_recip_service - send a bounce */
-
-int     bounce_recip_service(char *service, char *queue_name, char *queue_id,
-                                    char *recipient, char *bounced_addr,
-                                    char *why, int flush)
-{
-    VSTRING *buf = vstring_alloc(100);
-    int     bounce_status = 1;
-    int     postmaster_status = 1;
-    VSTREAM *bounce;
-    int     notify_mask = name_mask(mail_error_masks, var_notify_classes);
-    VSTRING *boundary = vstring_alloc(100);
-    char   *postmaster;
-
-    /*
-     * Unique string for multi-part message boundaries.
-     */
-    vstring_sprintf(boundary, "%s.%ld/%s",
-                   queue_id, (long) event_time(), var_myhostname);
-
-#define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
-#define NULL_CLEANUP_FLAGS     0
-#define BOUNCE_HEADERS         1
-#define BOUNCE_ALL             0
-
-    /*
-     * The choice of sender address depends on the recipient address. For a
-     * single bounce (a non-delivery notification to the message originator),
-     * the sender address is the empty string. For a double bounce (typically
-     * a failed single bounce, or a postmaster notification that was produced
-     * by any of the mail processes) the sender address is defined by the
-     * var_double_bounce_sender configuration variable. When a double bounce
-     * cannot be delivered, the queue manager blackholes the resulting triple
-     * bounce message.
-     */
-
-    /*
-     * Double bounce failed. Never send a triple bounce.
-     * 
-     * However, this does not prevent double bounces from bouncing on other
-     * systems. In order to cope with this, either the queue manager must
-     * recognize the double-bounce recipient address and discard mail, or
-     * every delivery agent must recognize the double-bounce sender address
-     * and substitute something else so mail does not come back at us.
-     */
-    if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
-       msg_warn("%s: undeliverable postmaster notification discarded",
-                queue_id);
-       bounce_status = 0;
-    }
-
-    /*
-     * Single bounce failed. Optionally send a double bounce to postmaster.
-     */
-#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
-#define SKIP_IF_BOUNCE (flush == 1 && (notify_mask & ANY_BOUNCE) == 0)
-#define SKIP_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY) == 0)
-
-    else if (*recipient == 0) {
-       if (SKIP_IF_BOUNCE || SKIP_IF_DELAY) {
-           bounce_status = 0;
-       } else {
-           postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
-           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
-                                                postmaster,
-                                                NULL_CLEANUP_FLAGS,
-                                                "BOUNCE")) != 0) {
-
-               /*
-                * Double bounce to Postmaster. This is the last opportunity
-                * for this message to be delivered. Send the text with
-                * reason for the bounce, and the headers of the original
-                * message. Don't bother sending the boiler-plate text.
-                */
-               if (!bounce_header(bounce, buf, postmaster,
-                                  STR(boundary), flush)
-                   && bounce_diagnostics(bounce, STR(boundary),
-                                         bounced_addr, why) == 0)
-                   bounce_original(service, bounce, buf, queue_name, queue_id,
-                                   STR(boundary),
-                                   flush ? BOUNCE_ALL : BOUNCE_HEADERS);
-               bounce_status = post_mail_fclose(bounce);
-           }
-       }
-    }
-
-    /*
-     * Non-bounce failed. Send a single bounce.
-     */
-    else {
-       if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
-                                            NULL_CLEANUP_FLAGS,
-                                            "BOUNCE")) != 0) {
-
-           /*
-            * Send the bounce message header, some boilerplate text that
-            * pretends that we are a polite mail system, the text with
-            * reason for the bounce, and a copy of the original message.
-            */
-           if (bounce_header(bounce, buf, recipient, STR(boundary), flush) == 0
-               && bounce_boilerplate(bounce, buf, STR(boundary), flush) == 0
-               && bounce_diagnostics(bounce, STR(boundary),
-                                     bounced_addr, why) == 0)
-               bounce_original(service, bounce, buf, queue_name, queue_id,
-                               STR(boundary),
-                               flush ? BOUNCE_ALL : BOUNCE_HEADERS);
-           bounce_status = post_mail_fclose(bounce);
-       }
-
-       /*
-        * Optionally, send a postmaster notice.
-        * 
-        * This postmaster notice is not critical, so if it fails don't
-        * retransmit the bounce that we just generated, just log a warning.
-        */
-#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
-#define WANT_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
-
-       if (bounce_status == 0 && (WANT_IF_BOUNCE || WANT_IF_DELAY)
-           && strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
-
-           /*
-            * Send the text with reason for the bounce, and the headers of
-            * the original message. Don't bother sending the boiler-plate
-            * text. This postmaster notice is not critical, so if it fails
-            * don't retransmit the bounce that we just generated, just log a
-            * warning.
-            */
-           postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
-           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
-                                                postmaster,
-                                                NULL_CLEANUP_FLAGS,
-                                                "BOUNCE")) != 0) {
-               if (!bounce_header(bounce, buf, postmaster,
-                                  STR(boundary), flush)
-                   && bounce_diagnostics(bounce, STR(boundary),
-                                         bounced_addr, why) == 0)
-                   bounce_original(service, bounce, buf, queue_name, queue_id,
-                                   STR(boundary), BOUNCE_HEADERS);
-               postmaster_status = post_mail_fclose(bounce);
-           }
-           if (postmaster_status)
-               msg_warn("postmaster notice failed while bouncing to %s",
-                        recipient);
-       }
-    }
-
-    /*
-     * Cleanup.
-     */
-    vstring_free(buf);
-    vstring_free(boundary);
-
-    return (bounce_status);
-}
index c298897078725d010f79553a7e131216fb10ca9a..369a3da0d0898fe0421c62bb4363eb83df32e9a0 100644 (file)
   */
 #include <vstring.h>
 
+ /*
+  * Global library.
+  */
+#include <bounce_log.h>
+
  /*
   * bounce_append_service.c
   */
@@ -23,11 +28,6 @@ extern int bounce_append_service(char *, char *, char *, char *);
   */
 extern int bounce_notify_service(char *, char *, char *, char *, int);
 
- /*
-  * bounce_recip_service.c
-  */
-extern int bounce_recip_service(char *, char *, char *, char *, char *, char *, int);
-
  /*
   * bounce_cleanup.c
   */
@@ -38,6 +38,33 @@ extern void bounce_cleanup_unregister(void);
 
 #define bounce_cleanup_registered() (bounce_cleanup_path != 0)
 
+ /*
+  * bounce_notify_util.c
+  */
+typedef struct {
+    const char *service;               /* bounce or defer */
+    const char *queue_name;            /* incoming, etc. */
+    const char *queue_id;              /* base name */
+    const char *mime_boundary;         /* for MIME */
+    int     flush;                     /* 0=defer, other=bounce */
+    VSTRING *buf;                      /* scratch pad */
+    VSTREAM *orig_fp;                  /* open queue file */
+    long    orig_offs;                 /* start of content */
+    time_t  arrival_time;              /* time of arrival */
+    BOUNCE_LOG *log_handle;                    /* open logfile */
+} BOUNCE_INFO;
+
+extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int);
+extern void bounce_mail_free(BOUNCE_INFO *);
+extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *);
+extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_recipient_log(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_diagnostic_log(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_header_dsn(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_recipient_dsn(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_diagnostic_dsn(VSTREAM *, BOUNCE_INFO *);
+extern int bounce_original(VSTREAM *, BOUNCE_INFO *, int);
+
 /* LICENSE
 /* .ad
 /* .fi
index 0d530da9b5ee5597cec6fea24ea87d2eb1860ba1..3d1e4d9cc231efa8b05a6cd437e6c81e8a47da88 100644 (file)
@@ -216,12 +216,13 @@ int     cleanup_close(CLEANUP_STATE *state)
 
     if (state->errs & CLEANUP_STAT_LETHAL) {
        if (CAN_BOUNCE()) {
-           if (bounce_recip(BOUNCE_FLAG_CLEAN,
-                            MAIL_QUEUE_INCOMING, state->queue_id,
-                            state->sender, state->recip ?
-                          state->recip : "unknown", "cleanup", state->time,
-                            "Message processing aborted: %s",
-                            cleanup_strerror(state->errs)) == 0) {
+           if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+                             state->recip ? state->recip : "unknown",
+                             "cleanup", state->time,
+                             "Message processing aborted: %s",
+                             cleanup_strerror(state->errs)) == 0
+               && bounce_flush(BOUNCE_FLAG_CLEAN, MAIL_QUEUE_INCOMING,
+                               state->queue_id, state->sender) == 0) {
                state->errs = 0;
            } else {
                msg_warn("%s: bounce message failure", state->queue_id);
index 9d522c7c50915770cf69954e09eca4d154503400..3168c858e067a4b533045b849471a6529de96f13 100644 (file)
@@ -17,7 +17,7 @@ SRCS  = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
        record.c remove.c resolve_clnt.c resolve_local.c rewrite_clnt.c \
        sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
        timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
-       tok822_resolve.c tok822_rewrite.c tok822_tree.c
+       tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c
 OBJS   = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        debug_peer.o debug_process.o defer.o deliver_completed.o \
        deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -36,7 +36,7 @@ OBJS  = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        record.o remove.o resolve_clnt.o resolve_local.o rewrite_clnt.o \
        sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
        timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
-       tok822_resolve.o tok822_rewrite.o tok822_tree.o
+       tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o
 HDRS   = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
        deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -51,7 +51,7 @@ HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        quote_821_local.h quote_822_local.h rec_streamlf.h rec_type.h \
        recipient_list.h record.h resolve_clnt.h resolve_local.h \
        rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
-       sys_exits.h timed_ipc.h tok822.h
+       sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -255,6 +255,15 @@ bounce.o: ../../include/vstream.h
 bounce.o: ../../include/iostuff.h
 bounce.o: defer.h
 bounce.o: bounce.h
+bounce_log.o: bounce_log.c
+bounce_log.o: ../../include/sys_defs.h
+bounce_log.o: ../../include/mymalloc.h
+bounce_log.o: ../../include/vstream.h
+bounce_log.o: ../../include/vbuf.h
+bounce_log.o: ../../include/vstring.h
+bounce_log.o: ../../include/vstring_vstream.h
+bounce_log.o: mail_queue.h
+bounce_log.o: bounce_log.h
 canon_addr.o: canon_addr.c
 canon_addr.o: ../../include/sys_defs.h
 canon_addr.o: ../../include/vstring.h
@@ -950,3 +959,9 @@ tok822_tree.o: ../../include/vstring.h
 tok822_tree.o: ../../include/vbuf.h
 tok822_tree.o: tok822.h
 tok822_tree.o: resolve_clnt.h
+xtext.o: xtext.c
+xtext.o: ../../include/sys_defs.h
+xtext.o: ../../include/vstream.h
+xtext.o: ../../include/vbuf.h
+xtext.o: ../../include/vstring.h
+xtext.o: xtext.h
index 122652d692abad91c23a589903fd10e7dae69340..75b07298d877b7e50faa59b863ff84a1adf4b5bd 100644 (file)
 /*     const char *queue;
 /*     const char *id;
 /*     const char *sender;
-/*
-/*     int     bounce_recip(flags, queue, id, sender, recipient, relay,
-/*                                     entry, format, ...)
-/*     int     flags;
-/*     const char *queue;
-/*     const char *id;
-/*     const char *sender;
-/*     const char *recipient;
-/*     const char *relay;
-/*     time_t  entry;
-/*     const char *format;
-/*
-/*     int     vbounce_recip(flags, queue, id, sender, recipient, relay,
-/*                                     entry, format, ap)
-/*     int     flags;
-/*     const char *queue;
-/*     const char *id;
-/*     const char *sender;
-/*     const char *recipient;
-/*     const char *relay;
-/*     time_t  entry;
-/*     const char *format;
-/*     va_list ap;
 /* DESCRIPTION
 /*     This module implements the client interface to the message
 /*     bounce service, which maintains a per-message log of status
@@ -65,9 +42,6 @@
 /*     the specified sender, including the bounce log that was
 /*     built with bounce_append().
 /*
-/*     bounce_recip() and vbounce_recipient() send one bounce
-/*     message immediately, without accessing a per-message bounce file.
-/*
 /*     Arguments:
 /* .IP flags
 /*     The bitwise OR of zero or more of the following (specify
@@ -209,61 +183,3 @@ int     bounce_flush(int flags, const char *queue, const char *id,
        return (-1);
     }
 }
-
-/* bounce_recip - send bounce for one recipient */
-
-int     bounce_recip(int flags, const char *queue, const char *id,
-                            const char *sender, const char *recipient,
-                            const char *relay, time_t entry,
-                            const char *fmt,...)
-{
-    va_list ap;
-    int     status;
-
-    va_start(ap, fmt);
-    status = vbounce_recip(flags, queue, id, sender, recipient, relay,
-                          entry, fmt, ap);
-    va_end(ap);
-    return (status);
-}
-
-/* vbounce_recip - send bounce for one recipient */
-
-int     vbounce_recip(int flags, const char *queue, const char *id,
-                             const char *sender, const char *recipient,
-                             const char *relay, time_t entry,
-                             const char *fmt, va_list ap)
-{
-    VSTRING *why;
-    int     status;
-    int     delay;
-
-    /*
-     * When we're pretending that we can't bounce, don't create a defer log
-     * file when we wouldn't keep the bounce log file. That's a lot of
-     * negatives in one sentence.
-     */
-    if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN))
-       return (-1);
-
-    delay = time((time_t *) 0) - entry;
-    why = vstring_alloc(100);
-    vstring_vsprintf(why, fmt, ap);
-    if (mail_command_write(MAIL_CLASS_PRIVATE, var_soft_bounce ?
-                          MAIL_SERVICE_DEFER : MAIL_SERVICE_BOUNCE,
-                          "%d %d %s %s %s %s %s", BOUNCE_CMD_RECIP,
-                          flags, queue, id, sender, recipient,
-                          vstring_str(why)) == 0) {
-       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s)",
-                id, recipient, relay, delay, var_soft_bounce ? "deferred" :
-                "bounced", vstring_str(why));
-       status = (var_soft_bounce ? -1 : 0);
-    } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
-       status = defer_append(flags, id, recipient, "bounce", delay,
-                             "bounce failed");
-    } else {
-       status = -1;
-    }
-    vstring_free(why);
-    return (status);
-}
index fd3623e98244e517e489f16efa4a55a18430246e..43ebc6040bbd5b00a26410d97e2f0545e5b1ca48 100644 (file)
@@ -42,7 +42,6 @@ extern int vbounce_recip(int, const char *, const char *, const char *,
 #define BOUNCE_CMD_FLUSH       1       /* send log */
 #define BOUNCE_CMD_WARN                2       /* send warning bounce, don't delete
                                         * log */
-#define BOUNCE_CMD_RECIP       3       /* immediate bounce, no logfile */
 
  /*
   * Flags.
diff --git a/postfix/src/global/bounce_log.c b/postfix/src/global/bounce_log.c
new file mode 100644 (file)
index 0000000..1bbcd23
--- /dev/null
@@ -0,0 +1,198 @@
+/*++
+/* NAME
+/*     bounce_log 3
+/* SUMMARY
+/*     bounce file API
+/* SYNOPSIS
+/*     #include <bounce_log.h>
+/*
+/*     typedef struct {
+/* .in +4
+/*         /* public members... */
+/*         const char *recipient;
+/*         const char *status;
+/*         const char *text;
+/* .in -4
+/*     } BOUNCE_LOG;
+/*
+/*     BOUNCE_LOG *bounce_log_open(queue, id, flags, mode)
+/*     const char *queue;
+/*     const char *id;
+/*     int     flags;
+/*     int     mode;
+/*
+/*     BOUNCE_LOG *bounce_log_read(bp)
+/*     BOUNCE_LOG *bp;
+/*
+/*     void    bounce_log_rewind(bp)
+/*     BOUNCE_LOG *bp;
+/*
+/*     void    bounce_log_close(bp)
+/*     BOUNCE_LOG *bp;
+/* DESCRIPTION
+/*     This module implements a bounce/defer logfile API. Information
+/*     is sanitized for control and non-ASCII characters. Currently,
+/*     only the reading end is implemented.
+/*
+/*     bounce_log_open() opens the named bounce or defer logfile
+/*     and returns a handle that must be used for further access.
+/*     The result is a null pointer if the file cannot be opened.
+/*     The caller is expected to inspect the errno code and deal
+/*     with the problem.
+/*
+/*     bounce_log_read() reads the next record from the bounce or defer
+/*     logfile (skipping over and warning about malformed data)
+/*     and breaks out the recipient address, the recipient status
+/*     and the text that explains why the recipient was undeliverable.
+/*     bounce_log_read() returns a null pointer when no recipient was read,
+/*     otherwise it returns its argument.
+/*
+/*     bounce_log_rewind() is a helper that seeks to the first recipient
+/*     in an open bounce or defer logfile (skipping over recipients that
+/*     are marked as done). The result is 0 in case of success, -1 in case 
+/*     of problems.
+/*
+/*     bounce_log_close() closes an open bounce or defer logfile and
+/*     releases memory for the specified handle. The result is non-zero
+/*     in case of I/O errors.
+/*
+/*     Arguments:
+/* .IP queue
+/*     The bounce or defer queue name.
+/* .IP id
+/*     The message queue id of bounce or defer logfile. This
+/*     file has the same name as the original message file.
+/* .IP flags
+/*     File open flags, as with open(2).
+/* .IP more
+/*     File permissions, as with open(2).
+/* .PP
+/*     Results:
+/* .IP recipient
+/*     The final recipient address.
+/* .IP text
+/*     The text that explains why the recipient was undeliverable.
+/* .IP status
+/*     String with DSN compatible status code (digit.digit.digit).
+/* .PP
+/*     Other fields will be added as the code evolves.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_queue.h>
+#include <bounce_log.h>
+
+/* Application-specific. */
+
+#define STR(x) vstring_str(x)
+
+/* bounce_log_open - open bounce read stream */
+
+BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id,
+                                   int flags, int mode)
+{
+    BOUNCE_LOG *bp;
+    VSTREAM *fp;
+
+#define STREQ(x,y)     (strcmp((x),(y)) == 0)
+
+    /*
+     * TODO: peek at the first byte to see if this is an old-style log
+     * (<recipient>: text) or a new-style extensible log with multiple
+     * attributes per recipient.
+     */
+    if ((fp = mail_queue_open(queue_name, queue_id, flags, mode)) == 0) {
+       return (0);
+    } else {
+       bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp));
+       bp->fp = fp;
+       bp->buf = vstring_alloc(100);
+       bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0";
+       return (bp);
+    }
+}
+
+/* bounce_log_read - read one record from bounce log file */
+
+BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
+{
+    char   *recipient;
+    char   *text;
+    char   *cp;
+
+    while (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF) {
+
+       if (STR(bp->buf)[0] == 0)
+           continue;
+
+       /*
+        * Sanitize.
+        */
+       cp = printable(STR(bp->buf), '?');
+
+       /*
+        * Find the recipient address.
+        */
+       if (*cp != '<') {
+           msg_warn("%s: malformed record: %.30s...",
+                    VSTREAM_PATH(bp->fp), cp);
+           continue;
+       }
+       recipient = cp + 1;
+       if ((cp = strstr(recipient, ">: ")) == 0) {
+           msg_warn("%s: malformed record: %.30s...",
+                    VSTREAM_PATH(bp->fp), cp);
+           continue;
+       }
+       *cp = 0;
+       bp->recipient = *recipient ? recipient : "(MAILER-DAEMON)";
+
+       /*
+        * Find the text that explains why mail was not deliverable.
+        */
+       text = cp + 2;
+       while (*text && ISSPACE(*text))
+           text++;
+       bp->text = text;
+
+       return (bp);
+    }
+    return (0);
+}
+
+/* bounce_log_close - close bounce reader stream */
+
+int     bounce_log_close(BOUNCE_LOG *bp)
+{
+    int     ret;
+
+    ret = vstream_fclose(bp->fp);
+    vstring_free(bp->buf);
+    myfree((char *) bp);
+    return (ret);
+}
diff --git a/postfix/src/global/bounce_log.h b/postfix/src/global/bounce_log.h
new file mode 100644 (file)
index 0000000..7b949e9
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _BOUNCE_LOG_H_INCLUDED_
+#define _BOUNCE_LOG_H_INCLUDED_
+
+/*++
+/* NAME
+/*     bounce_log 3h
+/* SUMMARY
+/*     bounce file reader
+/* SYNOPSIS
+/*     #include <bounce_log.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+  * External interface.
+  */
+typedef struct {
+    /* Private. */
+    VSTREAM *fp;                       /* open file */
+    VSTRING *buf;                      /* I/O buffer */
+    /* Public. */
+    const char *recipient;             /* final recipient */
+    const char *status;                        /* recipient status */
+    const char *text;                  /* why undeliverable */
+} BOUNCE_LOG;
+
+extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int);
+extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *);
+extern int bounce_log_close(BOUNCE_LOG *);
+
+#define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET)
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 3fe444180805ad83b64debae810821421346a284..c6cebe89fa623fc88e0ad4046ffddba1c430e75e 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20000923"
+#define DEF_MAIL_VERSION       "Snapshot-20000924"
 extern char *var_mail_version;
 
 /* LICENSE
diff --git a/postfix/src/global/xtext.c b/postfix/src/global/xtext.c
new file mode 100644 (file)
index 0000000..32a51e4
--- /dev/null
@@ -0,0 +1,87 @@
+/*++
+/* NAME
+/*     xtext 3
+/* SUMMARY
+/*     translate characters according to RFC 1894
+/* SYNOPSIS
+/*     #include <xtext.h>
+/*
+/*     VSTRING *xtext(result, original)
+/*     VSTRING *result;
+/*     const char *original;
+/* DESCRIPTION
+/*     xtext() takes a null-terminated string, and produces a translation
+/*     according to RFC 1894 (DSN).
+/* BUGS
+/*     Cannot replace null characters.
+/*
+/*     Does not insert CR LF SPACE to limit output line length.
+/* SEE ALSO
+/*     RFC 1894, Delivery Status Notifications
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include <vstream.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+
+/* Global library. */
+
+#include <xtext.h>
+
+/* xtext - translate text according to RFC 1894 */
+
+VSTRING *xtext(VSTRING *result, const char *original)
+{
+    const char *cp;
+    int     ch;
+
+    /*
+     * Preliminary implementation. ASCII specific!!
+     */
+    VSTRING_RESET(result);
+    for (cp = original; (ch = *(unsigned char *) cp) != 0; cp++) {
+       if (ch == '+' || ch == '\\' || ch == '(' || ch < 33 || ch > 126)
+           vstring_sprintf_append(result, "+%02X", ch);
+       else
+           VSTRING_ADDCH(result, ch);
+    }
+    VSTRING_TERMINATE(result);
+
+    return (result);
+}
+
+#ifdef TEST
+
+#define STR(x) vstring_str(x)
+
+#include <vstream.h>
+
+int     main(int unused_argc, char **unused_argv)
+{
+    VSTRING *ibuf = vstring_alloc(100);
+    VSTRING *obuf = vstring_alloc(100);
+
+    while (vstring_fgets(ibuf, VSTREAM_IN)) {
+       vstream_fputs(STR(xtext(obuf, STR(ibuf))));
+       vstream_fflush(VSTREAM_OUT);
+    }
+    vstring_free(ibuf);
+    vstring_free(obuf);
+    return (0);
+}
+
+#endif
diff --git a/postfix/src/global/xtext.h b/postfix/src/global/xtext.h
new file mode 100644 (file)
index 0000000..3c02057
--- /dev/null
@@ -0,0 +1,30 @@
+/*++
+/* NAME
+/*     xtext 3h
+/* SUMMARY
+/*     translate characters according to RFC 1894
+/* SYNOPSIS
+/*     #include <xtext.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstring.h>
+
+ /*
+  * External interface.
+  */
+extern VSTRING *xtext(VSTRING *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
index cfcaf2dafdd9b8501428297b8e27fd8fd3b5b97d..3418afb2bc0b352fa2792dc549fc07594f5ef15e 100644 (file)
@@ -63,6 +63,7 @@ showq.o: ../../include/vstream.h
 showq.o: ../../include/vstring_vstream.h
 showq.o: ../../include/stringops.h
 showq.o: ../../include/mymalloc.h
+showq.o: ../../include/htable.h
 showq.o: ../../include/mail_queue.h
 showq.o: ../../include/mail_open_ok.h
 showq.o: ../../include/mail_proto.h
@@ -73,5 +74,5 @@ showq.o: ../../include/mail_scan_dir.h
 showq.o: ../../include/mail_conf.h
 showq.o: ../../include/record.h
 showq.o: ../../include/rec_type.h
-showq.o: ../../include/htable.h
+showq.o: ../../include/bounce_log.h
 showq.o: ../../include/mail_server.h
index d43bccab80a57b3ff12686a297069c22f3dc1fdd..06fdb1c2533ece30cb3a251985b1ea46ff284660 100644 (file)
@@ -67,6 +67,7 @@
 #include <vstring_vstream.h>
 #include <stringops.h>
 #include <mymalloc.h>
+#include <htable.h>
 
 /* Global library. */
 
@@ -79,7 +80,7 @@
 #include <mail_conf.h>
 #include <record.h>
 #include <rec_type.h>
-#include <htable.h>
+#include <bounce_log.h>
 
 /* Single-threaded server skeleton. */
 
@@ -92,7 +93,7 @@ int     var_dup_filter_limit;
 #define STRING_FORMAT  "%-10s %8s %-20s %s\n"
 #define DATA_FORMAT    "%-10s%c%8ld %20.20s %s\n"
 
-static void showq_reasons(VSTREAM *, VSTREAM *, HTABLE *);
+static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *);
 
 static void showq_report(VSTREAM *client, char *queue, char *id,
                                 VSTREAM *qfile, long size)
@@ -102,7 +103,7 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
     time_t  arrival_time = 0;
     char   *start;
     long    msg_size = 0;
-    VSTREAM *logfile;
+    BOUNCE_LOG *logfile;
     HTABLE *dup_filter = 0;
     char    status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : ' ');
 
@@ -150,11 +151,10 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
         */
        if (rec_type == REC_TYPE_FROM
            && dup_filter == 0
-           && (logfile = mail_queue_open(MAIL_QUEUE_DEFER, id,
-                                         O_RDONLY, 0)) != 0) {
+           && (logfile = bounce_log_open(MAIL_QUEUE_DEFER, id, O_RDONLY, 0)) != 0) {
            dup_filter = htable_create(var_dup_filter_limit);
            showq_reasons(client, logfile, dup_filter);
-           if (vstream_fclose(logfile))
+           if (bounce_log_close(logfile))
                msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
        }
     }
@@ -165,88 +165,37 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
 
 /* showq_reasons - show deferral reasons */
 
-static void showq_reasons(VSTREAM *client, VSTREAM *logfile, HTABLE *dup_filter)
+static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, HTABLE *dup_filter)
 {
-    VSTRING *buf = vstring_alloc(100);
-    char   *recipient;
-    char   *reason;
     char   *saved_reason = 0;
-    char   *cp;
-
-    /*
-     * XXX Kluge alert. The defer log is an unstructured file. This has the
-     * advantage that information is directly suitable for human consumption,
-     * and that a process may crash while updating the file - the result will
-     * still be usable. The downside of using an unstructured file is that it
-     * is hard to process such information mechanically, like we do here. In
-     * the end this will have to be a structured file anyway so we can do
-     * DSN.
-     */
-#define STR    vstring_str
-
-    while (vstring_get_nonl(buf, logfile) != VSTREAM_EOF) {
-
-       /*
-        * Do this now so the string won't be reallocated.
-        */
-       VSTRING_ADDCH(buf, ')');
-       VSTRING_TERMINATE(buf);
+    int     padding;
 
-       cp = printable(STR(buf), '?');
-       if (cp[1] == 0)
-           continue;
-
-       /*
-        * Find the recipient address.
-        */
-       if (*cp != '<') {
-           msg_warn("%s: bad defer record: %.30s...",
-                    VSTREAM_PATH(logfile), cp);
-           continue;
-       }
-       recipient = cp + 1;
-       if ((cp = strstr(recipient, ">:")) == 0) {
-           msg_warn("%s: bad defer record: %.30s...",
-                    VSTREAM_PATH(logfile), cp);
-           continue;
-       }
-       *cp = 0;
+    while (bounce_log_read(bp) != 0) {
 
        /*
         * Update the duplicate filter.
         */
-       if (*recipient == 0)                    /* can't happen? */
-           recipient = "(MAILER-DAEMON)";
        if (var_dup_filter_limit == 0
            || dup_filter->used < var_dup_filter_limit)
-           if (htable_locate(dup_filter, recipient) == 0)
-               htable_enter(dup_filter, recipient, (char *) 0);
-
-       /*
-        * Find the reason for deferral. Put parentheses around it.
-        */
-       reason = cp + 2;
-       while (*reason && ISSPACE(*reason))
-           reason++;
-       reason -= 1;
-       *reason = '(';
+           if (htable_locate(dup_filter, bp->recipient) == 0)
+               htable_enter(dup_filter, bp->recipient, (char *) 0);
 
        /*
         * Don't print the reason when the previous recipient had the same
         * problem.
         */
-       if (saved_reason == 0 || strcmp(saved_reason, reason) != 0) {
+       if (saved_reason == 0 || strcmp(saved_reason, bp->text) != 0) {
            if (saved_reason)
                myfree(saved_reason);
-           saved_reason = mystrdup(reason);
-           vstream_fprintf(client, "%78s\n", reason);
+           saved_reason = mystrdup(bp->text);
+           if ((padding = 76 - strlen(saved_reason)) < 0)
+               padding = 0;
+           vstream_fprintf(client, "%*s(%s)\n", padding, "", saved_reason);
        }
-       vstream_fprintf(client, STRING_FORMAT, "", "", "",
-                       printable(recipient, '?'));
+       vstream_fprintf(client, STRING_FORMAT, "", "", "", bp->recipient);
     }
     if (saved_reason)
        myfree(saved_reason);
-    vstring_free(buf);
 }
 
 
index ed7b2172214da11fb14215d3d427c38a027c1036..4221e3807c866d949480e0c29f21788938e042a4 100644 (file)
@@ -837,7 +837,7 @@ typedef int pid_t;
 #if __GNUC__ == 2 && __GNUC_MINOR__ >= 7
 #define SCANFLIKE(x,y) __attribute__ ((format (scanf, (x), (y))))
 #else
-#define SCANFLIKE
+#define SCANFLIKE(x,y)
 #endif
 #endif