]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20051112
authorWietse Venema <wietse@porcupine.org>
Sat, 12 Nov 2005 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:31:41 +0000 (06:31 +0000)
31 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/Makefile.in
postfix/conf/master.cf
postfix/conf/postfix-files
postfix/html/bounce.8.html
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/man/man8/bounce.8
postfix/proto/postconf.proto
postfix/src/bounce/Makefile.in
postfix/src/bounce/bounce.c
postfix/src/bounce/bounce_notify_service.c
postfix/src/bounce/bounce_notify_util.c
postfix/src/bounce/bounce_notify_verp.c
postfix/src/bounce/bounce_service.h
postfix/src/bounce/bounce_template.c [new file with mode: 0644]
postfix/src/bounce/bounce_trace_service.c
postfix/src/bounce/bounce_warn_service.c
postfix/src/bounce/dict_ml.c [new file with mode: 0644]
postfix/src/bounce/dict_ml.h [new file with mode: 0644]
postfix/src/bounce/fix-template.pl [new file with mode: 0644]
postfix/src/cleanup/cleanup_envelope.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/util/Makefile.in
postfix/src/util/allascii.c [new file with mode: 0644]
postfix/src/util/allspace.c [new file with mode: 0644]
postfix/src/util/dict.c
postfix/src/util/format_tv.c
postfix/src/util/stringops.h

index df2a7dea4fec2bb6963dbb9efc12f96ca4a0fccb..00e85e8cd1ad9ac932247e8dd407fdf25852fec3 100644 (file)
@@ -21,6 +21,9 @@
 -TBOUNCE_LOG_DSN_BUF
 -TBOUNCE_LOG_RCPT_BUF
 -TBOUNCE_STAT
+-TBOUNCE_TEMPLATE
+-TBOUNCE_TIME_DIVISOR
+-TBOUNCE_TIME_PARAMETER
 -TCFG_PARSER
 -TCIDR_MATCH
 -TCLEANUP_STATE
index 82380f62268cb0df693b8051607ed9290e669666..8c4e6961e5dba92fcac7f76ba9bd75ce90a46b6b 100644 (file)
@@ -11338,9 +11338,11 @@ Apologies for any names omitted.
        delay_logging_resolution_limit parameter, which specifies
        the maximal number of digits after the decimal point.
 
-       Bugfix: under unlikely conditions two messages could get
-       the same message ID. Found by Victor. Files: global/mail_stream.c,
-       global/mail_queue.c.
+       Bugfix: two messages could get the same message ID due to
+       a race condition. This time window was increased when queue
+       file creation was postponed from MAIL FROM until the first
+       accepted RCPT TO.  The window is closed again. Found by
+       Victor. Files: global/mail_stream.c, global/mail_queue.c.
 
 20051109
 
@@ -11353,6 +11355,27 @@ Apologies for any names omitted.
        Bugfix: XCLIENT broke when reverse hostname support was added.
        Fix by Tomoyuki Sakurai. File: smtpd/smtpd.c.
 
+20051110
+
+       Workaround: don't set the delay warning timer for messages
+       from inside or from outside that have the null sender as
+       recipient. This was a waste of time, because the warning
+       would always be discarded.  File: cleanup/cleanup_envelope.c.
+
+       Feature: the built-in mail delivery status notification
+       text is now implemented by built-in templates. Files:
+       bounce/bounce_template.c, bounce/bounce_notify_util.c.
+
+20051112
+
+       Feature (grumble): configurable bounce message templates
+       based on contribution by Nicolas Riendeau. I kept the general
+       format of his templates, but placed them together in one
+       file to reduce process initialization overhead. Files:
+       bounce/bounce_template.c, bounce/dict_ml.c (to be moved to
+       library if useful enough). A sample bounce message template
+       file is installed as $config_directory/bounce.cf.default.
+
 Open problems:
 
        "postsuper -r" no longer resets the message arrival time,
index fde9ca2a25fd885ddfa9d8129e9f19bcf98ec899..6ff54224df0d52e58fb0bfdf138bbbc0789f7c07 100644 (file)
@@ -74,7 +74,7 @@ tidy: clean
            *.bak */*.bak */*/*.bak \
            make.err */make.err */*/make.err \
            *.gmon */*.gmon */*/*.gmon \
-           conf/main.cf.default
+           conf/main.cf.default conf/bounce.cf.default
        find . -type s -print | xargs rm -f
        find . -type d -print | xargs chmod 755
        find . -type f -print | xargs chmod a+r
index 3833ad6b4b8d83e8d53f6a4c7e1c17df2a71eea3..b597e1a37099dbbcacf1a020aba9407a6770ac27 100644 (file)
@@ -7,14 +7,14 @@
 #               (yes)   (yes)   (yes)   (never) (100)
 # ==========================================================================
 smtp      inet  n       -       n       -       -       smtpd
-#submission inet n      -       n       -       -       smtpd
-#      -o smtpd_etrn_restrictions=reject
-#      -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-#smtps    inet  n       -       n       -       -       smtpd
-#  -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
-#submission   inet    n       -       n       -       -       smtpd
-#  -o smtpd_etrn_restrictions=reject
-#  -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes
+#submission inet n       -       n       -       -       smtpd
+#  -o smtpd_enforce_tls=yes
+#  -o smtpd_sasl_auth_enable=yes
+#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+#smtps     inet  n       -       n       -       -       smtpd
+#  -o smtpd_tls_wrappermode=yes
+#  -o smtpd_sasl_auth_enable=yes
+#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 #628      inet  n       -       n       -       -       qmqpd
 pickup    fifo  n       -       n       60      1       pickup
 cleanup   unix  n       -       n       -       0       cleanup
index 73492dd8d7685cd3c4fd4af5f050301c64e99da0..0ff7c876e2fa1959ff5f00dbf5f064d7db546313 100644 (file)
@@ -104,14 +104,15 @@ $config_directory/LICENSE:f:root:-:644
 $config_directory/TLS_LICENSE:f:root:-:644
 $config_directory/access:f:root:-:644:p
 $config_directory/aliases:f:root:-:644:p
+$config_directory/bounce.cf.default:f:root:-:644
 $config_directory/canonical:f:root:-:644:p
 $config_directory/cidr_table:f:root:-:644:o
-$config_directory/generics:f:root:-:644:o
 $config_directory/generic:f:root:-:644:p
+$config_directory/generics:f:root:-:644:o
 $config_directory/header_checks:f:root:-:644:p
 $config_directory/install.cf:f:root:-:644:o
-$config_directory/main.cf:f:root:-:644:p
 $config_directory/main.cf.default:f:root:-:644
+$config_directory/main.cf:f:root:-:644:p
 $config_directory/makedefs.out:f:root:-:644
 $config_directory/master.cf:f:root:-:644:p
 $config_directory/pcre_table:f:root:-:644:o
index 8211f059b86a930cb53cfcfca83ac8072360cbbd..7fa0568034f8c5680e4666e938525c80afb0809b 100644 (file)
@@ -78,18 +78,22 @@ BOUNCE(8)                                                            BOUNCE(8)
               The maximal amount of original message text that is
               sent in a non-delivery notification.
 
+       <b>bounce_template_file (empty)</b>
+              Pathname  of  a configuration file with bounce mes-
+              sage templates.
+
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix main.cf and
+              The default location of  the  Postfix  main.cf  and
               master.cf configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_notice_recipient">delay_notice_recipient</a> (postmaster)</b>
-              The recipient of postmaster notifications with  the
-              message  headers  of  mail that cannot be delivered
+              The  recipient of postmaster notifications with the
+              message headers of mail that  cannot  be  delivered
               within $<a href="postconf.5.html#delay_warning_time">delay_warning_time</a> time units.
 
        <b><a href="postconf.5.html#deliver_lock_attempts">deliver_lock_attempts</a> (20)</b>
@@ -97,7 +101,7 @@ BOUNCE(8)                                                            BOUNCE(8)
               sive lock on a mailbox file or <a href="bounce.8.html"><b>bounce</b>(8)</a> logfile.
 
        <b><a href="postconf.5.html#deliver_lock_delay">deliver_lock_delay</a> (1s)</b>
-              The  time  between attempts to acquire an exclusive
+              The time between attempts to acquire  an  exclusive
               lock on a mailbox file or <a href="bounce.8.html"><b>bounce</b>(8)</a> logfile.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -110,36 +114,36 @@ BOUNCE(8)                                                            BOUNCE(8)
               bounced mail.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The  maximum  amount  of  time that an idle Postfix
-              daemon process waits for the next  service  request
+              The maximum amount of time  that  an  idle  Postfix
+              daemon  process  waits for the next service request
               before exiting.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The  maximal number of connection requests before a
+              The maximal number of connection requests before  a
               Postfix daemon process terminates.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The list of error classes that are reported to  the
+              The  list of error classes that are reported to the
               postmaster.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The  process  ID  of  a  Postfix  command or daemon
+              The process ID  of  a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The process name of a  Postfix  command  or  daemon
+              The  process  name  of  a Postfix command or daemon
               process.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The  location of the Postfix top-level queue direc-
+              The location of the Postfix top-level queue  direc-
               tory.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The mail system  name  that  is  prepended  to  the
-              process  name  in  syslog  records, so that "smtpd"
+              The  mail  system  name  that  is  prepended to the
+              process name in syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>FILES</b>
@@ -155,7 +159,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>
index 7bea38b3a190c08310afb97db49bfb08b977e130..1d721f5397f0cf62bc7887aef13767c7c42dccc0 100644 (file)
@@ -1102,6 +1102,17 @@ this limit, then you should increase the <a href="postconf.5.html#mime_nesting_l
 proportionally.  </p>
 
 
+</DD>
+
+<DT><b><a name="bounce_template_file">bounce_template_file</a>
+(default: empty)</b></DT><DD>
+
+<p> Pathname of a configuration file with bounce message templates.
+</p>
+
+<p> This feature is available in Postfix 2.3 and later.  </p>
+
+
 </DD>
 
 <DT><b><a name="broken_sasl_auth_clients">broken_sasl_auth_clients</a>
index b1b5b6768d53a90419bc044e87b53597e4059c78..fcc3accaa28e7ecac43a6cbe4f5c3b9ca3105bf3 100644 (file)
@@ -599,6 +599,10 @@ The maximal amount of original message text that is sent in a
 non-delivery notification. Specify a byte count. If you increase
 this limit, then you should increase the mime_nesting_limit value
 proportionally.
+.SH bounce_template_file (default: empty)
+Pathname of a configuration file with bounce message templates.
+.PP
+This feature is available in Postfix 2.3 and later.
 .SH broken_sasl_auth_clients (default: no)
 Enable inter-operability with SMTP clients that implement an obsolete
 version of the AUTH command (RFC 2554). Examples of such clients
index adf9df566de5eb6d8f9a58535785a2a9842ba8ec..de843697f1480151e452362e61a7ce3492143803 100644 (file)
@@ -73,6 +73,8 @@ transcripts of mail that Postfix did not receive.
 .IP "\fBbounce_size_limit (50000)\fR"
 The maximal amount of original message text that is sent in a
 non-delivery notification.
+.IP "\fBbounce_template_file (empty)\fR"
+Pathname of a configuration file with bounce message templates.
 .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
 The default location of the Postfix main.cf and master.cf
 configuration files.
index 802f413b1c134d395a6f77cb323ed189e030c9b8..80119f197e4889b5f1ba15d79755772ebcb8ff19 100644 (file)
@@ -8675,3 +8675,11 @@ precision.  </p>
 </ul>
 
 <p> This feature is available in Postfix 2.3 and later.  </p>
+
+%PARAM bounce_template_file empty
+
+<p> Pathname of a configuration file with bounce message templates.
+</p>
+
+<p> This feature is available in Postfix 2.3 and later.  </p>
+
index f8b0a6e43f50c5cf262dffc7b71831f257d24f44..f6f3c614157ab8ca486985d452238b73ef03dbfd 100644 (file)
@@ -1,16 +1,19 @@
 SHELL  = /bin/sh
 SRCS   = bounce.c bounce_append_service.c bounce_notify_service.c \
        bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c \
-       bounce_one_service.c bounce_warn_service.c bounce_trace_service.c
+       bounce_one_service.c bounce_warn_service.c bounce_trace_service.c \
+       bounce_template.c dict_ml.c
 OBJS   = bounce.o bounce_append_service.o bounce_notify_service.o \
        bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o \
-       bounce_one_service.o bounce_warn_service.o bounce_trace_service.o
+       bounce_one_service.o bounce_warn_service.o bounce_trace_service.o \
+       bounce_template.o dict_ml.o
 HDRS   = 
 TESTSRC        = 
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
 TESTPROG=
 PROG   = bounce
+SAMPLES        = ../../conf/bounce.cf.default
 INC_DIR        = ../../include
 LIBS   = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
 
@@ -19,6 +22,10 @@ LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
 $(PROG):       $(OBJS) $(LIBS)
        $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
 
+../../conf/bounce.cf.default: $(PROG) fix-template.pl
+       rm -f $@
+       ./$(PROG) -Szn default | perl fix-template.pl >$@
+
 $(OBJS): ../../conf/makedefs.out
 
 Makefile: Makefile.in
@@ -26,9 +33,9 @@ Makefile: Makefile.in
 
 test:  $(TESTPROG)
 
-tests: test
+tests: update template_test
 
-update: ../../libexec/$(PROG)
+update: ../../libexec/$(PROG) $(SAMPLES)
 
 ../../libexec/$(PROG): $(PROG)
        cp $(PROG) ../../libexec
@@ -50,6 +57,11 @@ clean:
 
 tidy:  clean
 
+template_test:
+       ./bounce -Szn default >junk
+       ./bounce -Szn actual -o bounce_template_file=`pwd`/junk | diff junk -
+       rm -f junk
+
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
        set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -230,6 +242,34 @@ bounce_one_service.o: ../../include/vstream.h
 bounce_one_service.o: ../../include/vstring.h
 bounce_one_service.o: bounce_one_service.c
 bounce_one_service.o: bounce_service.h
+bounce_template.o: ../../include/argv.h
+bounce_template.o: ../../include/attr.h
+bounce_template.o: ../../include/bounce_log.h
+bounce_template.o: ../../include/cleanup_user.h
+bounce_template.o: ../../include/dict.h
+bounce_template.o: ../../include/dsn.h
+bounce_template.o: ../../include/dsn_buf.h
+bounce_template.o: ../../include/iostuff.h
+bounce_template.o: ../../include/is_header.h
+bounce_template.o: ../../include/mac_expand.h
+bounce_template.o: ../../include/mac_parse.h
+bounce_template.o: ../../include/mail_addr.h
+bounce_template.o: ../../include/mail_conf.h
+bounce_template.o: ../../include/mail_params.h
+bounce_template.o: ../../include/mail_proto.h
+bounce_template.o: ../../include/msg.h
+bounce_template.o: ../../include/mymalloc.h
+bounce_template.o: ../../include/post_mail.h
+bounce_template.o: ../../include/rcpt_buf.h
+bounce_template.o: ../../include/recipient_list.h
+bounce_template.o: ../../include/stringops.h
+bounce_template.o: ../../include/sys_defs.h
+bounce_template.o: ../../include/vbuf.h
+bounce_template.o: ../../include/vstream.h
+bounce_template.o: ../../include/vstring.h
+bounce_template.o: bounce_service.h
+bounce_template.o: bounce_template.c
+bounce_template.o: dict_ml.h
 bounce_trace_service.o: ../../include/attr.h
 bounce_trace_service.o: ../../include/bounce_log.h
 bounce_trace_service.o: ../../include/cleanup_user.h
@@ -274,3 +314,15 @@ bounce_warn_service.o: ../../include/vstream.h
 bounce_warn_service.o: ../../include/vstring.h
 bounce_warn_service.o: bounce_service.h
 bounce_warn_service.o: bounce_warn_service.c
+dict_ml.o: ../../include/argv.h
+dict_ml.o: ../../include/dict.h
+dict_ml.o: ../../include/iostuff.h
+dict_ml.o: ../../include/msg.h
+dict_ml.o: ../../include/stringops.h
+dict_ml.o: ../../include/sys_defs.h
+dict_ml.o: ../../include/vbuf.h
+dict_ml.o: ../../include/vstream.h
+dict_ml.o: ../../include/vstring.h
+dict_ml.o: ../../include/vstring_vstream.h
+dict_ml.o: dict_ml.c
+dict_ml.o: dict_ml.h
index 14ed9d6ca48d209a3fe1590dd68cb0ec64cc5009..de4219a0631fe9c6dc6e54d1e5be1ea0473bba3e 100644 (file)
@@ -61,6 +61,8 @@
 /* .IP "\fBbounce_size_limit (50000)\fR"
 /*     The maximal amount of original message text that is sent in a
 /*     non-delivery notification.
+/* .IP "\fBbounce_template_file (empty)\fR"
+/*     Pathname of a configuration file with bounce message templates.
 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
 /*     The default location of the Postfix main.cf and master.cf
 /*     configuration files.
@@ -168,6 +170,7 @@ char   *var_notify_classes;
 char   *var_bounce_rcpt;
 char   *var_2bounce_rcpt;
 char   *var_delay_rcpt;
+char   *var_bounce_tmpl;
 
  /*
   * We're single threaded, so we can avoid some memory allocation overhead.
@@ -441,6 +444,16 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
     if (mail_queue_name_ok(service_name) == 0)
        msg_fatal("malformed service name: %s", service_name);
 
+    /*
+     * Special case: dump the built-in templates. This is not part of the
+     * public interface.
+     */
+    if (strcmp(service_name, "default") == 0) {
+       bounce_template_dump_default(VSTREAM_OUT);
+       vstream_fflush(VSTREAM_OUT);
+       exit(0);
+    }
+
     /*
      * Read and validate the first parameter of the client request. Let the
      * request-specific protocol routines take care of the remainder.
@@ -490,6 +503,29 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
     }
 }
 
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *service_name, char **unused_argv)
+{
+
+    /*
+     * Load the alternate message files (if specified) before entering the ch
+     * root jail.
+     */
+    if (*var_bounce_tmpl)
+       bounce_template_load(var_bounce_tmpl);
+
+    /*
+     * Special case: dump the actual templates. This is not part of the
+     * public interface.
+     */
+    if (strcmp(service_name, "actual") == 0) {
+       bounce_template_dump_actual(VSTREAM_OUT);
+       vstream_fflush(VSTREAM_OUT);
+       exit(0);
+    }
+}
+
 /* post_jail_init - initialize after entering chroot jail */
 
 static void post_jail_init(char *unused_name, char **unused_argv)
@@ -527,6 +563,7 @@ int     main(int argc, char **argv)
        VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
        VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
        VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0,
+       VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0,
        0,
     };
 
@@ -537,6 +574,7 @@ int     main(int argc, char **argv)
                       MAIL_SERVER_INT_TABLE, int_table,
                       MAIL_SERVER_STR_TABLE, str_table,
                       MAIL_SERVER_TIME_TABLE, time_table,
+                      MAIL_SERVER_PRE_INIT, pre_jail_init,
                       MAIL_SERVER_POST_INIT, post_jail_init,
                       MAIL_SERVER_UNLIMITED,
                       0);
index 1cf6aeb5de1c5fecf088c068c6c4cba12465342e..415bdeec411dc38a76926dcc21241e5c09f3419b 100644 (file)
@@ -127,7 +127,7 @@ int     bounce_notify_service(int flags, char *service, char *queue_name,
      * notification is enabled.
      */
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
-                                  encoding, dsn_envid, BOUNCE_REPORT_FAIL);
+                                  encoding, dsn_envid, FAIL_TEMPLATE());
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_TRACE_FLAGS       0
index 1b5d70bf3eb7428298a7c430eb6947a861f4ac34..27a2cd7a0f7497ab67c8a4ab2314b5d162ee8966 100644 (file)
 /*     } BOUNCE_INFO;
 /*
 /*     BOUNCE_INFO *bounce_mail_init(service, queue_name, queue_id,
-/*                                     encoding, dsn_envid, report_type)
+/*                                     encoding, dsn_envid, template)
 /*     const char *service;
 /*     const char *queue_name;
 /*     const char *queue_id;
 /*     const char *encoding;
 /*     const char *dsn_envid;
-/*     int     report_type;
+/*     const BOUNCE_TEMPLATE *template;
 /*
 /*     BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id, encoding,
 /*                                     dsn_envid, dsn_notify, rcpt, dsn)
 /*     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. The report type is BOUNCE_REPORT_WARN
-/*     for delayed mail, BOUNCE_REPORT_FAIL for undeliverable mail,
-/*     BOUNCE_REPORT_SUCCESS for "success" delivery notification,
-/*     or BOUNCE_REPORT_OTHER for other status reports.
+/*     undeliverable message.
 /*
 /*     bounce_mail_one_init() provides the same function for only
 /*     one recipient that is not read from bounce logfile. It
-/*     assumes a report type of BOUNCE_REPORT_FAIL.
+/*     assumes a template type of FAIL_TEMPLATE().
 /*
 /*     bounce_mail_free() releases memory allocated by bounce_mail_init()
 /*     and closes any files opened by bounce_mail_init().
@@ -211,7 +208,7 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
                                              const char *queue_id,
                                              const char *encoding,
                                              const char *dsn_envid,
-                                             int report_type,
+                                             const BOUNCE_TEMPLATE *template,
                                              BOUNCE_LOG *log_handle)
 {
     BOUNCE_INFO *bounce_info;
@@ -239,7 +236,7 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
        bounce_info->dsn_envid = dsn_envid;
     else
        bounce_info->dsn_envid = 0;
-    bounce_info->report_type = report_type;
+    bounce_info->template = template;
     bounce_info->buf = vstring_alloc(100);
     bounce_info->sender = vstring_alloc(100);
     bounce_info->arrival_time = 0;
@@ -327,7 +324,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service,
                                      const char *queue_id,
                                      const char *encoding,
                                      const char *dsn_envid,
-                                     int report_type)
+                                     const BOUNCE_TEMPLATE *template)
 {
     BOUNCE_INFO *bounce_info;
     BOUNCE_LOG *log_handle;
@@ -344,7 +341,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service,
        && errno != ENOENT)
        msg_fatal("open %s %s: %m", service, queue_id);
     bounce_info = bounce_mail_alloc(service, queue_name, queue_id, encoding,
-                                   dsn_envid, report_type, log_handle);
+                                   dsn_envid, template, log_handle);
     return (bounce_info);
 }
 
@@ -366,7 +363,7 @@ BOUNCE_INFO *bounce_mail_one_init(const char *queue_name,
      */
     log_handle = bounce_log_forge(rcpt, dsn);
     bounce_info = bounce_mail_alloc("none", queue_name, queue_id, encoding,
-                                dsn_envid, BOUNCE_REPORT_FAIL, log_handle);
+                                   dsn_envid, FAIL_TEMPLATE(), log_handle);
     return (bounce_info);
 }
 
@@ -393,6 +390,7 @@ void    bounce_mail_free(BOUNCE_INFO *bounce_info)
 int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
                              const char *dest)
 {
+    int     postmaster_copy;
 
     /*
      * Print a minimal bounce header. The cleanup service will add other
@@ -400,44 +398,21 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
      */
 #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->report_type == BOUNCE_REPORT_FAIL) {
-       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.
+     * XXX This should be caller specified.
      */
-    else if (bounce_info->report_type == BOUNCE_REPORT_WARN) {
-       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)");
-    }
-
-    /*
-     * DSN SUCCESS report.
-     */
-    else if (bounce_info->report_type == BOUNCE_REPORT_SUCCESS) {
-       post_mail_fputs(bounce,
-                       "Subject: Successful Mail Delivery Report");
-    }
+    postmaster_copy =
+       (bounce_info->template->postmaster_subject != 0
+        && (dest == var_bounce_rcpt || dest == var_2bounce_rcpt
+            || dest == var_delay_rcpt));
 
     /*
-     * Address verification report, verbose delivery report.
+     * Generic headers.
      */
-    else {
-       post_mail_fputs(bounce, "Subject: Mail Delivery Status Report");
-    }
-
+    post_mail_fprintf(bounce, "From: %s", bounce_info->template->from);
+    post_mail_fprintf(bounce, "Subject: %s", postmaster_copy ?
+                     bounce_info->template->postmaster_subject :
+                     bounce_info->template->subject);
     post_mail_fprintf(bounce, "To: %s",
                      STR(quote_822_local(bounce_info->buf, dest)));
 
@@ -460,7 +435,8 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
     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_fprintf(bounce, "Content-Type: %s; charset=%s",
+                     "text/plain", bounce_info->template->charset);
     post_mail_fputs(bounce, "");
 
     return (vstream_ferror(bounce));
@@ -472,64 +448,9 @@ 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.
+     * Print the boiler-plate text.
      */
-#define UNDELIVERED(type) \
-       ((type) == BOUNCE_REPORT_FAIL || (type) == BOUNCE_REPORT_WARN)
-
-    post_mail_fprintf(bounce, "This is the %s program at host %s.",
-                     var_mail_name, var_myhostname);
-    post_mail_fputs(bounce, "");
-    if (bounce_info->report_type == BOUNCE_REPORT_FAIL) {
-       post_mail_fputs(bounce,
-            "I'm sorry to have to inform you that your message could not");
-       post_mail_fputs(bounce,
-           "be delivered to one or more recipients. It's attached below.");
-    } else if (bounce_info->report_type == BOUNCE_REPORT_WARN) {
-       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 %.1f hours.",
-                         var_delay_warn_time / 3600.0);
-       post_mail_fprintf(bounce,
-                         "It will be retried until it is %.1f days old.",
-                         var_max_queue_time / 86400.0);
-    } else if (bounce_info->report_type == BOUNCE_REPORT_SUCCESS) {
-       post_mail_fputs(bounce,
-                       "Your message was successfully delivered to the destination(s) listed");
-       post_mail_fputs(bounce,
-                       "below. In the case of delivery to mailbox you will receive no further");
-       post_mail_fputs(bounce,
-           "notifications. In the case of other deliveries you may still");
-       post_mail_fputs(bounce,
-                       "receive notifications of mail delivery errors.");
-
-    } else {
-       post_mail_fputs(bounce,
-               "Enclosed is the mail delivery report that you requested.");
-    }
-    if (UNDELIVERED(bounce_info->report_type)) {
-       post_mail_fputs(bounce, "");
-       post_mail_fprintf(bounce,
-                         "For further assistance, please send mail to <%s>",
-                         MAIL_ADDR_POSTMASTER);
-       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 attached returned message.");
-    }
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
+    bounce_template_expand(bounce, bounce_info->template);
     return (vstream_ferror(bounce));
 }
 
@@ -602,7 +523,7 @@ int     bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
      */
     if (bounce_info->log_handle == 0
        || bounce_log_rewind(bounce_info->log_handle)) {
-       if (bounce_info->report_type == BOUNCE_REPORT_FAIL) {
+       if (bounce_info->template == FAIL_TEMPLATE()) {
            post_mail_fputs(bounce, "\t--- Delivery report unavailable ---");
            count = 1;                          /* XXX don't abort */
        }
@@ -694,7 +615,7 @@ int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
                          bounce_info->log_handle->rcpt.orig_addr);
     }
     post_mail_fprintf(bounce, "Action: %s",
-                     bounce_info->report_type == BOUNCE_REPORT_FAIL ?
+                     bounce_info->template == FAIL_TEMPLATE() ?
                      "failed" : bounce_info->log_handle->dsn.action);
     post_mail_fprintf(bounce, "Status: %s",
                      bounce_info->log_handle->dsn.status);
@@ -716,7 +637,7 @@ int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
     post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
                      bounce_info->log_handle->log_time);
 #endif
-    if (bounce_info->report_type == BOUNCE_REPORT_WARN)
+    if (bounce_info->template == DELAY_TEMPLATE())
        post_mail_fprintf(bounce, "Will-Retry-Until: %s",
                 mail_date(bounce_info->arrival_time + var_max_queue_time));
     return (vstream_ferror(bounce));
@@ -740,7 +661,7 @@ int     bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
      */
     if (bounce_info->log_handle == 0
        || bounce_log_rewind(bounce_info->log_handle)) {
-       if (bounce_info->report_type == BOUNCE_REPORT_FAIL)
+       if (bounce_info->template == FAIL_TEMPLATE())
            count = 1;                          /* XXX don't abort */
     } else {
        while (bounce_log_read(bounce_info->log_handle) != 0) {
@@ -776,10 +697,13 @@ int     bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
     /*
      * MIME headers.
      */
+#define UNDELIVERED(template) \
+        ((template) == FAIL_TEMPLATE() || (template) == DELAY_TEMPLATE())
+
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
     post_mail_fprintf(bounce, "Content-Description: %s%s",
-                     UNDELIVERED(bounce_info->report_type) ?
+                     UNDELIVERED(bounce_info->template) ?
                      "Undelivered " : "",
                      headers_only == DSN_RET_HDRS ?
                      "Message Headers" : "Message");
index 97873bc5f949451a2af2884e61d85e8714ba4ed4..2c938be8d2f887cdfb954e0e32c9502699b9cbf8 100644 (file)
@@ -109,7 +109,7 @@ int     bounce_notify_verp(int flags, char *service, char *queue_name,
      * Initialize. Open queue file, bounce log, etc.
      */
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
-                                  encoding, dsn_envid, BOUNCE_REPORT_FAIL);
+                                  encoding, dsn_envid, FAIL_TEMPLATE());
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_TRACE_FLAGS       0
index a47fc5db8ea8cf1f7ed146fe927e6a0453e3414c..e0034c08f6375f808eb9d2de7725659cd374c0cc 100644 (file)
@@ -58,6 +58,65 @@ extern void bounce_cleanup_unregister(void);
 
 #define bounce_cleanup_registered() (bounce_cleanup_path != 0)
 
+ /*
+  * bounce_template.c
+  */
+typedef struct {
+    const char *class;                 /* template type */
+    const char *charset;               /* character set */
+    const char *encoding;              /* 7bit or 8bit */
+    const char *from;                  /* originator */
+    const char *subject;               /* general subject line */
+    const char *postmaster_subject;    /* postmaster subject line */
+    const char **message_text;         /* message text */
+} BOUNCE_TEMPLATE;
+
+extern void bounce_template_load(const char *);
+extern void bounce_template_expand(VSTREAM *, const BOUNCE_TEMPLATE *);
+extern const BOUNCE_TEMPLATE *bounce_template_find(const char *, const BOUNCE_TEMPLATE *);
+extern void bounce_template_dump_default(VSTREAM *);
+extern void bounce_template_dump_actual(VSTREAM *);
+
+#define BOUNCE_TEMPLATE_DICT   "bounce_templates"
+#define BOUNCE_TMPL_DICT_FAIL  "fail_template"
+#define BOUNCE_TMPL_DICT_DELAY "delay_template"
+#define BOUNCE_TMPL_DICT_SUCCESS "success_template"
+#define BOUNCE_TMPL_DICT_VERIFY        "verify_template"
+
+#define FAIL_TEMPLATE() \
+    (bounce_fail_template ? bounce_fail_template : \
+       (bounce_fail_template = \
+           bounce_template_find(BOUNCE_TMPL_DICT_FAIL, \
+               &def_bounce_fail_template)))
+
+#define DELAY_TEMPLATE() \
+    (bounce_delay_template ? bounce_delay_template : \
+       (bounce_delay_template = \
+           bounce_template_find(BOUNCE_TMPL_DICT_DELAY, \
+               &def_bounce_delay_template)))
+
+#define SUCCESS_TEMPLATE() \
+    (bounce_success_template ? bounce_success_template : \
+       (bounce_success_template = \
+           bounce_template_find(BOUNCE_TMPL_DICT_SUCCESS, \
+               &def_bounce_success_template)))
+
+#define VERIFY_TEMPLATE() \
+    (bounce_verify_template ? bounce_verify_template : \
+       (bounce_verify_template = \
+           bounce_template_find(BOUNCE_TMPL_DICT_VERIFY, \
+               &def_bounce_verify_template)))
+
+extern const BOUNCE_TEMPLATE *bounce_fail_template;
+extern const BOUNCE_TEMPLATE *bounce_delay_template;
+extern const BOUNCE_TEMPLATE *bounce_success_template;
+extern const BOUNCE_TEMPLATE *bounce_verify_template;
+
+extern const BOUNCE_TEMPLATE def_bounce_fail_template;
+extern const BOUNCE_TEMPLATE def_bounce_delay_template;
+extern const BOUNCE_TEMPLATE def_bounce_success_template;
+extern const BOUNCE_TEMPLATE def_bounce_verify_template;
+
  /*
   * bounce_notify_util.c
   */
@@ -68,7 +127,7 @@ typedef struct {
     const char *mime_encoding;         /* null or encoding */
     const char *dsn_envid;             /* DSN envelope ID */
     const char *mime_boundary;         /* for MIME */
-    int     report_type;               /* see below */
+    const BOUNCE_TEMPLATE *template;   /* see above */
     VSTRING *buf;                      /* scratch pad */
     VSTRING *sender;                   /* envelope sender */
     VSTREAM *orig_fp;                  /* open queue file */
@@ -81,7 +140,7 @@ typedef struct {
 
  /* */
 
-extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, const char *, int);
+extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, const char *, const BOUNCE_TEMPLATE *);
 extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, RECIPIENT *, DSN *);
 extern void bounce_mail_free(BOUNCE_INFO *);
 extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *);
@@ -95,14 +154,6 @@ extern int bounce_original(VSTREAM *, BOUNCE_INFO *, int);
 extern void bounce_delrcpt(BOUNCE_INFO *);
 extern void bounce_delrcpt_one(BOUNCE_INFO *);
 
- /*
-  * Report types.
-  */
-#define BOUNCE_REPORT_FAIL     0       /* undeliverable mail */
-#define BOUNCE_REPORT_WARN     1       /* delayed mail */
-#define BOUNCE_REPORT_SUCCESS  2       /* success */
-#define BOUNCE_REPORT_OTHER    3       /* other status */
-
 /* LICENSE
 /* .ad
 /* .fi
diff --git a/postfix/src/bounce/bounce_template.c b/postfix/src/bounce/bounce_template.c
new file mode 100644 (file)
index 0000000..78ccea3
--- /dev/null
@@ -0,0 +1,547 @@
+/*++
+/* NAME
+/*     bounce_template 3
+/* SUMMARY
+/*     bounce template processing
+/* SYNOPSIS
+/*     #include "bounce_service.h"
+/*
+/*     void    bounce_template_load(path)
+/*     const char *path;
+/*
+/*     const BOUNCE_TEMPLATE *FAIL_TEMPLATE()
+/*
+/*     const BOUNCE_TEMPLATE *DELAY_TEMPLATE()
+/*
+/*     const BOUNCE_TEMPLATE *SUCCESS_TEMPLATE()
+/*
+/*     const BOUNCE_TEMPLATE *VERIFY_TEMPLATE()
+/*
+/*     void    bounce_template_expand(stream, template)
+/*     VSTREAM *stream;
+/*     BOUNCE_TEMPLATE *template;
+/* AUXILIARY FUNCTIONS
+/*     void    bounce_template_dump_default(stream)
+/*     VSTREAM *stream;
+/*
+/*     void    bounce_template_dump_actual(stream)
+/*     VSTREAM *stream;
+/* DESCRIPTION
+/*     This module implements the built-in and external bounce
+/*     message template support.
+/*
+/*     bounce_template_load() reads bounce templates from the
+/*     specified file.
+/*
+/*     FAIL_TEMPLATE() etc. look up the corresponding bounce
+/*     template from file, or use a built-in template when no
+/*     template was specified externally.
+/*
+/*     bounce_template_expand() expands the body text of the
+/*     specified template and writes the result to the specified
+/*     queue file record stream.
+/*
+/*     bounce_template_dump_default() dumps the built-in default templates
+/*     to the specified stream. This can be used to generate input
+/*     for the default bounce service configuration file.
+/*
+/*     bounce_template_dump_actual() dumps the actually-used templates
+/*     to the specified stream. This can be used to verify that
+/*     the bounce server correctly reads its own bounce_template_dump_default()
+/*     output.
+/* DIAGNOSTICS
+/*     Fatal error: error opening template file, out of memory,
+/*     undefined macro name in template.
+/* BUGS
+/* 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>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mac_expand.h>
+#include <split_at.h>
+#include <stringops.h>
+#include <mymalloc.h>
+#include <dict_ml.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_conf.h>
+#include <mail_addr.h>
+#include <post_mail.h>
+#include <is_header.h>
+#include <mail_proto.h>
+
+/* Application-specific. */
+
+#include <bounce_service.h>
+
+ /*
+  * The fail template is for permanent failure.
+  */
+static const char *def_bounce_fail_body[];
+
+const BOUNCE_TEMPLATE def_bounce_fail_template = {
+    "fail",
+    "us-ascii",
+    MAIL_ATTR_ENC_7BIT,
+    MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
+    "Undelivered Mail Returned to Sender",
+    "Postmaster Copy: Undelivered Mail",
+    def_bounce_fail_body,
+};
+
+static const char *def_bounce_fail_body[] = {
+    "This is the $mail_name program at host $myhostname.",
+    "",
+    "I'm sorry to have to inform you that your message could not",
+    "be delivered to one or more recipients. It's attached below.",
+    "",
+    "For further assistance, please send mail to <" MAIL_ADDR_POSTMASTER ">",
+    "",
+    "If you do so, please include this problem report. You can",
+    "delete your own text from the attached returned message.",
+    "",
+    "                   The $mail_name program",
+    0,
+};
+
+ /*
+  * The delay template is for delayed mail notifications.
+  */
+static const char *def_bounce_delay_body[];
+
+const BOUNCE_TEMPLATE def_bounce_delay_template = {
+    "delay",
+    "us-ascii",
+    MAIL_ATTR_ENC_7BIT,
+    MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
+    "Delayed Mail (still being retried)",
+    "Postmaster Warning: Delayed Mail",
+    def_bounce_delay_body,
+};
+
+static const char *def_bounce_delay_body[] = {
+    "This is the $mail_name program at host $myhostname.",
+    "",
+    "####################################################################",
+    "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #",
+    "####################################################################",
+    "",
+    "Your message could not be delivered for $delay_warning_time_hours hour(s).",
+    "It will be retried until it is $maximal_queue_lifetime_days day(s) old.",
+    "",
+    "For further assistance, please send mail to <" MAIL_ADDR_POSTMASTER ">",
+    "",
+    "If you do so, please include this problem report. You can",
+    "delete your own text from the attached returned message.",
+    "",
+    "                   The $mail_name program",
+    0,
+};
+
+ /*
+  * The success template is for "delivered", "expanded" and "relayed" success
+  * notifications.
+  */
+static const char *def_bounce_success_body[];
+
+const BOUNCE_TEMPLATE def_bounce_success_template = {
+    "success",
+    "us-ascii",
+    MAIL_ATTR_ENC_7BIT,
+    MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
+    "Successful Mail Delivery Report",
+    0,
+    def_bounce_success_body,
+};
+
+static const char *def_bounce_success_body[] = {
+    "This is the $mail_name program at host $myhostname.",
+    "",
+    "Your message was successfully delivered to the destination(s)",
+    "listed below. If the message was delivered to mailbox you will",
+    "receive no further notifications. Otherwise you may still receive",
+    "notifications of mail delivery errors from other systems.",
+    "",
+    "                   The $mail_name program",
+    0,
+};
+
+ /*
+  * The "verify" template is for verbose delivery (sendmail -v) and for
+  * address verification (sendmail -bv).
+  */
+static const char *def_bounce_verify_body[];
+
+const BOUNCE_TEMPLATE def_bounce_verify_template = {
+    "verify",
+    "us-ascii",
+    MAIL_ATTR_ENC_7BIT,
+    MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
+    "Mail Delivery Status Report",
+    0,
+    def_bounce_verify_body,
+};
+
+static const char *def_bounce_verify_body[] = {
+    "This is the $mail_name program at host $myhostname.",
+    "",
+    "Enclosed is the mail delivery report that you requested.",
+    "",
+    "                   The $mail_name program",
+    0,
+};
+
+ /*
+  * Pointers, so that we can override a built-in template with one from file
+  * without clobbering the built-in template.
+  */
+const BOUNCE_TEMPLATE *bounce_fail_template;
+const BOUNCE_TEMPLATE *bounce_delay_template;
+const BOUNCE_TEMPLATE *bounce_success_template;
+const BOUNCE_TEMPLATE *bounce_verify_template;
+
+ /*
+  * The following tables implement support for bounce template expansions of
+  * $<parameter_name>_days ($<parameter_name>_hours, etc.). The expansion of
+  * these is the actual parameter value divided by the number of seconds in a
+  * day (hour, etc.), so that we can produce nicely formatted bounce messages
+  * with time values converted into the appropriate units.
+  * 
+  * Ideally, the bounce template processor would strip the _days etc. suffix
+  * from the parameter name, and use the parameter name to look up the actual
+  * parameter value and its default value (the default value specifies the
+  * default time unit of that parameter (seconds, minutes, etc.), and allows
+  * us to convert the parameter string value into the corresponding number of
+  * seconds). The bounce template processor would then use the _hours etc.
+  * suffix from the bounce template to divide this number by the number of
+  * seconds in an hour, etc. and produce the number that is needed for the
+  * template.
+  * 
+  * Unfortunately, there exists no code to look up default values by parameter
+  * name. If such code existed, then we could do the _days, _hours, etc.
+  * conversion with every main.cf time parameter without having to know in
+  * advance what time parameter names exist.
+  * 
+  * So we have to either maintain our own table of all time related main.cf
+  * parameter names and defaults (like the postconf command does) or we make
+  * a special case for a few parameters of special interest.
+  * 
+  * We go for the second solution. There are only a few parameters that need
+  * this treatment, and there will be more special cases when individual
+  * queue files get support for individual expiration times, and when other
+  * queue file information needs to be reported in bounce template messages.
+  * 
+  * A really lame implementation would simply strip the optional s, h, d, etc.
+  * suffix from the actual (string) parameter value and not do any conversion
+  * at all to hours, days or weeks. But then the information in delay warning
+  * notices could be seriously incorrect.
+  */
+typedef struct {
+    const char *suffix;                        /* days, hours, etc. */
+    int     suffix_len;                        /* byte count */
+    int     divisor;                   /* divisor */
+} BOUNCE_TIME_DIVISOR;
+
+#define STRING_AND_LEN(x) (x), (sizeof(x) - 1)
+
+static BOUNCE_TIME_DIVISOR time_divisors[] = {
+    STRING_AND_LEN("seconds"), 1,
+    STRING_AND_LEN("minutes"), 60,
+    STRING_AND_LEN("hours"), 60 * 60,
+    STRING_AND_LEN("days"), 24 * 60 * 60,
+    STRING_AND_LEN("weeks"), 7 * 24 * 60 * 60,
+    0, 0,
+};
+
+ /*
+  * The few special-case main.cf parameters that have support for _days, etc.
+  * suffixes for automatic conversion when expanded into a bounce template.
+  */
+typedef struct {
+    const char *param_name;            /* parameter name */
+    int     param_name_len;            /* name length */
+    int    *value;                     /* parameter value */
+} BOUNCE_TIME_PARAMETER;
+
+static BOUNCE_TIME_PARAMETER time_parameter[] = {
+    STRING_AND_LEN(VAR_DELAY_WARN_TIME), &var_delay_warn_time,
+    STRING_AND_LEN(VAR_MAX_QUEUE_TIME), &var_max_queue_time,
+    0, 0,
+};
+
+ /*
+  * SLMs.
+  */
+#define STR(x) vstring_str(x)
+
+/* bounce_template_lookup - lookup $name value */
+
+static const char *bounce_template_lookup(const char *key, int unused_mode,
+                                                 char *context)
+{
+    BOUNCE_TEMPLATE *template = (BOUNCE_TEMPLATE *) context;
+    BOUNCE_TIME_PARAMETER *bp;
+    BOUNCE_TIME_DIVISOR *bd;
+    static VSTRING *buf;
+    int     result;
+
+    /*
+     * Look for parameter names that can have a time unit suffix, and scale
+     * the time value according to the suffix.
+     */
+    for (bp = time_parameter; bp->param_name; bp++) {
+       if (strncmp(key, bp->param_name, bp->param_name_len) == 0
+           && key[bp->param_name_len] == '_') {
+           for (bd = time_divisors; bd->suffix; bd++) {
+               if (strcmp(key + bp->param_name_len + 1, bd->suffix) == 0) {
+                   result = bp->value[0] / bd->divisor;
+                   if (result > 999 && bd->divisor < 86400) {
+                       msg_warn("excessive result \"%d\" in %s bounce "
+                                "template conversion of parameter \"%s\"",
+                                result, template->class, key);
+                       msg_warn("please increase time unit \"%s\" of \"%s\" "
+                                "in bounce template file", bd->suffix, key);
+                   } else if (result == 0 && bd->divisor > 1) {
+                       msg_warn("zero result in %s bounce template "
+                                "conversion of parameter \"%s\"",
+                                template->class, key);
+                       msg_warn("please reduce time unit \"%s\" of \"%s\" "
+                                "in bounce template file", bd->suffix, key);
+                   }
+                   if (buf == 0)
+                       buf = vstring_alloc(10);
+                   vstring_sprintf(buf, "%d", result);
+                   return (STR(buf));
+               }
+           }
+           msg_fatal("unrecognized suffix \"%s\" in template parameter \"%s\"",
+                     key + bp->param_name_len + 1, key);
+       }
+    }
+    return (mail_conf_lookup_eval(key));
+}
+
+/* bounce_template_expand - expand template body */
+
+void    bounce_template_expand(VSTREAM *stream, const BOUNCE_TEMPLATE *template)
+{
+    VSTRING *buf = vstring_alloc(100);
+    const char **cpp;
+    int     stat;
+    const char *filter = "\t !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
+
+#define NO_CONTEXT      ((char *) 0)
+
+    for (cpp = template->message_text; *cpp; cpp++) {
+       stat = mac_expand(buf, *cpp, MAC_EXP_FLAG_NONE, filter,
+                         bounce_template_lookup, (char *) template);
+       if (stat & MAC_PARSE_ERROR)
+           msg_fatal("bad $name syntax in %s template: %s",
+                     template->class, *cpp);
+       if (stat & MAC_PARSE_UNDEF)
+           msg_fatal("undefined $name in %s template: %s",
+                     template->class, *cpp);
+       post_mail_fputs(stream, STR(buf));
+    }
+    vstring_free(buf);
+}
+
+/* bounce_template_load - load template(s) from file */
+
+void    bounce_template_load(const char *path)
+{
+    static int once = 0;
+
+    /*
+     * Split the input stream into chunks between begin/end markers, ignoring
+     * comment lines.
+     */
+    if (once++ > 0)
+       msg_panic("bounce_template_load: multiple calls");
+    dict_ml_load_file(BOUNCE_TEMPLATE_DICT, path);
+}
+
+/* bounce_template_find - return default or user-specified template */
+
+const BOUNCE_TEMPLATE *bounce_template_find(const char *template_name,
+                                       const BOUNCE_TEMPLATE *def_template)
+{
+    BOUNCE_TEMPLATE *tp;
+    char   *tval;
+    char   *cp;
+    char  **cpp;
+    int     cpp_len;
+    int     cpp_used;
+    int     hlen;
+    char   *hval;
+
+    /*
+     * Look up a non-default template. Once we found it we are going to
+     * destroy it; no-one will access this data again.
+     */
+    if (*var_bounce_tmpl == 0
+       || (tval = (char *) dict_lookup(BOUNCE_TEMPLATE_DICT, template_name)) == 0)
+       return (def_template);
+
+    /*
+     * Initialize a new template. We're not going to use the message text
+     * from the default template.
+     */
+    tp = (BOUNCE_TEMPLATE *) mymalloc(sizeof(*tp));
+    *tp = *def_template;
+
+#define CLEANUP_AND_RETURN(x) do { \
+       myfree((char *) tp); \
+       return (x); \
+    } while (0)
+
+
+    /*
+     * Parse pseudo-header labels and values.
+     */
+#define GETLINE(line, buf) \
+       (((line) = (buf)) ? ((buf) = split_at((buf), '\n'), (line)) : 0)
+/*#define GETLINE(line, buf) (line = mystrtok(&buf, "\n"))*/
+
+    while ((GETLINE(cp, tval)) != 0 && (hlen = is_header(cp)) > 0) {
+       for (hval = cp + hlen; *hval && (*hval == ':' || ISSPACE(*hval)); hval++)
+           *hval = 0;
+       if (*hval == 0) {
+           msg_warn("empty \"%s\" header value in %s template "
+                    "-- ignoring this template", cp, template_name);
+           CLEANUP_AND_RETURN(def_template);
+       }
+       if (!allascii(hval)) {
+           msg_warn("non-ASCII \"%s\" header value in %s template "
+                    "-- ignoring this template", cp, template_name);
+           CLEANUP_AND_RETURN(def_template);
+       }
+       if (strcasecmp("charset", cp) == 0) {
+           tp->charset = hval;
+       } else if (strcasecmp("from", cp) == 0) {
+           tp->from = hval;
+       } else if (strcasecmp("subject", cp) == 0) {
+           tp->subject = hval;
+       } else if (strcasecmp("postmaster-subject", cp) == 0) {
+           if (tp->postmaster_subject == 0) {
+               msg_warn("\"%s\" header label in %s template is not applicable "
+                        "-- ignoring this template", cp, template_name);
+               CLEANUP_AND_RETURN(def_template);
+           }
+           tp->postmaster_subject = hval;
+       } else {
+           msg_warn("unknown \"%s\" header label in %s template "
+                    "-- ignoring this template", cp, template_name);
+           CLEANUP_AND_RETURN(def_template);
+       }
+    }
+
+    /*
+     * Skip blank lines between header and message text.
+     */
+    while (cp && (*cp == 0 || allspace(cp)))
+       (void) GETLINE(cp, tval);
+    if (cp == 0) {
+       msg_warn("missing message text in %s template "
+                "-- ignoring this template", template_name);
+       CLEANUP_AND_RETURN(def_template);
+    }
+
+    /*
+     * Is this 7bit or 8bit text? If the character set is US-ASCII, then
+     * don't allow 8bit text.
+     */
+#define NON_ASCII(p) (*(p) && !allascii((p)))
+
+    if (NON_ASCII(cp) || NON_ASCII(tval)) {
+       if (strcasecmp(tp->charset, "us-ascii") == 0) {
+           msg_warn("8-bit message text in %s template", template_name);
+           msg_warn("please specify a charset value other than us-ascii");
+           msg_warn("-- ignoring this template for now");
+           CLEANUP_AND_RETURN(def_template);
+       }
+       tp->encoding = MAIL_ATTR_ENC_8BIT;
+    }
+
+    /*
+     * Collect the message text and null-terminate the result.
+     */
+    cpp_len = 10;
+    cpp_used = 0;
+    cpp = (char **) mymalloc(sizeof(*cpp) * cpp_len);
+    while (cp) {
+       cpp[cpp_used++] = cp;
+       if (cpp_used >= cpp_len) {
+           cpp = (char **) myrealloc((char *) cpp,
+                                     sizeof(*cpp) * 2 * cpp_len);
+           cpp_len *= 2;
+       }
+       (void) GETLINE(cp, tval);
+    }
+    cpp[cpp_used] = 0;
+    tp->message_text = (const char **) cpp;
+
+    return (tp);
+}
+
+/* print_template - dump one template */
+
+static void print_template(VSTREAM *stream, const BOUNCE_TEMPLATE *tp)
+{
+    const char **cpp;
+
+    vstream_fprintf(stream, "%s_template = <<EOF\n", tp->class);
+    vstream_fprintf(stream, "Charset: %s\n", tp->charset);
+    vstream_fprintf(stream, "From: %s\n", tp->from);
+    vstream_fprintf(stream, "Subject: %s\n", tp->subject);
+    if (tp->postmaster_subject)
+       vstream_fprintf(stream, "Postmaster-Subject: %s\n",
+                       tp->postmaster_subject);
+    vstream_fprintf(stream, "\n");
+    for (cpp = tp->message_text; *cpp; cpp++)
+       vstream_fprintf(stream, "%s\n", *cpp);
+    vstream_fprintf(stream, "EOF\n");
+    vstream_fflush(stream);
+}
+
+/* bounce_template_dump_actual - dump actual templates to stream */
+
+void    bounce_template_dump_actual(VSTREAM *stream)
+{
+    print_template(VSTREAM_OUT, FAIL_TEMPLATE());
+    print_template(VSTREAM_OUT, DELAY_TEMPLATE());
+    print_template(VSTREAM_OUT, SUCCESS_TEMPLATE());
+    print_template(VSTREAM_OUT, VERIFY_TEMPLATE());
+}
+
+/* bounce_template_dump_default - dump built-in templates to stream */
+
+void    bounce_template_dump_default(VSTREAM *stream)
+{
+    print_template(VSTREAM_OUT, &def_bounce_fail_template);
+    print_template(VSTREAM_OUT, &def_bounce_delay_template);
+    print_template(VSTREAM_OUT, &def_bounce_success_template);
+    print_template(VSTREAM_OUT, &def_bounce_verify_template);
+}
index 0212932aa6dbc98f41d96d6559eb486170f5d9b7..c760f16188fe5756690bca039474bcfe6ea5995d 100644 (file)
@@ -106,8 +106,8 @@ int     bounce_trace_service(int flags, char *service, char *queue_name,
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
                                   encoding, dsn_envid,
                                   flags & NON_DSN_FLAGS ?
-                                  BOUNCE_REPORT_OTHER :
-                                  BOUNCE_REPORT_SUCCESS);
+                                  VERIFY_TEMPLATE() :
+                                  SUCCESS_TEMPLATE());
 
     /*
      * XXX With multi-recipient mail some queue file recipients may have
index 2a964ceec3afcd95a75cc4801dc43ba8f798ddb5..229965fd8731bfc9ac0ba76ebe99641fc9f737f7 100644 (file)
@@ -117,7 +117,7 @@ int     bounce_warn_service(int unused_flags, char *service, char *queue_name,
      * notify_classes restrictions.
      */
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
-                                  encoding, dsn_envid, BOUNCE_REPORT_WARN);
+                                  encoding, dsn_envid, DELAY_TEMPLATE());
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_TRACE_FLAGS       0
diff --git a/postfix/src/bounce/dict_ml.c b/postfix/src/bounce/dict_ml.c
new file mode 100644 (file)
index 0000000..d7be3f1
--- /dev/null
@@ -0,0 +1,179 @@
+/*++
+/* NAME
+/*     dict 3
+/* SUMMARY
+/*     dictionary manager, multi-line entry support
+/* SYNOPSIS
+/*     #include <dict_ml.h>
+/*
+/*     void    dict_ml_load_file(dict_name, path)
+/*     const char *dict_name;
+/*     const char *path;
+/*
+/*     void    dict_ml_load_fp(dict_name, fp)
+/*     const char *dict_name;
+/*     VSTREAM *fp;
+/* DESCRIPTION
+/*     This module implements input routines for dictionaries
+/*     with single-line and multi-line values.
+/* .IP \(bu
+/*     Single-line values are specified as "name = value".
+/*     Like dict_load_file() and dict_load_fp(), leading and
+/*     trailing whitespace is stripped from name and value.
+/* .IP \(bu
+/*     Multi-line values are specified as:
+/*
+/* .na
+/* .nf
+/* .in +4
+/*     name = <<EOF
+/*     text here...
+/*     EOF
+/* .in -4
+/* .ad
+/* .fi
+/*
+/*     Leading or trailing white space is not stripped from
+/*     multi-line values.
+/* .IP \(bu
+/*     The following input is ignored outside "<<" context: empty
+/*     lines, all whitespace lines, and lines whose first
+/*     non-whitespace character is "#".
+/* .PP
+/*     dict_ml_load_file() enters (name, value) pairs from the
+/*     specified file to the specified dictionary.
+/*
+/*     dict_ml_load_fp() reads (name, value) pairs from an open
+/*     stream. It has the same semantics as dict_ml_load_file().
+/* SEE ALSO
+/*     dict(3)
+/* DIAGNOSTICS
+/*     Fatal errors: out of memory, malformed macro name, missing
+/*     or mal-formed end marker.
+/* 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 <sys/stat.h>
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <iostuff.h>
+#include <stringops.h>
+#include <dict.h>
+#include <dict_ml.h>
+
+#define STR(x) vstring_str(x)
+
+/* dict_ml_load_file - load table from file */
+
+void    dict_ml_load_file(const char *dict_name, const char *path)
+{
+    VSTREAM *fp;
+    struct stat st;
+    time_t  before;
+    time_t  after;
+
+    /*
+     * Read the file again if it is hot. This may result in reading a partial
+     * parameter name when a file changes in the middle of a read.
+     */
+    for (before = time((time_t *) 0); /* see below */ ; before = after) {
+       if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
+           msg_fatal("open %s: %m", path);
+       dict_ml_load_fp(dict_name, fp);
+       if (fstat(vstream_fileno(fp), &st) < 0)
+           msg_fatal("fstat %s: %m", path);
+       if (vstream_ferror(fp) || vstream_fclose(fp))
+           msg_fatal("read %s: %m", path);
+       after = time((time_t *) 0);
+       if (st.st_mtime < before - 1 || st.st_mtime > after)
+           break;
+       if (msg_verbose)
+           msg_info("pausing to let %s cool down", path);
+       doze(300000);
+    }
+}
+
+/* dict_ml_load_fp - load table from stream */
+
+void    dict_ml_load_fp(const char *dict_name, VSTREAM *fp)
+{
+    VSTRING *line_buf;
+    char   *member_name;
+    VSTRING *multi_line_buf = 0;
+    VSTRING *saved_member_name = 0;
+    VSTRING *saved_end_marker = 0;
+    char   *value;
+    int     lineno;
+    const char *err;
+    char   *cp;
+
+    line_buf = vstring_alloc(100);
+    lineno = 1;
+    while (vstring_get_nonl(line_buf, fp) > 0) {
+       lineno++;
+       cp = STR(line_buf) + strspn(STR(line_buf), " \t\n\v\f\r");
+       if (*cp == 0 || *cp == '#')
+           continue;
+       if ((err = split_nameval(STR(line_buf), &member_name, &value)) != 0)
+           msg_fatal("%s, line %d: %s: \"%s\"",
+                     VSTREAM_PATH(fp), lineno, err, STR(line_buf));
+       if (value[0] == '<' && value[1] == '<') {
+           value += 2;
+           while (ISSPACE(*value))
+               value++;
+           if (*value == 0)
+               msg_fatal("%s, line %d: missing end marker after <<",
+                         VSTREAM_PATH(fp), lineno);
+           if (!ISALNUM(*value))
+               msg_fatal("%s, line %d: malformed end marker after <<",
+                         VSTREAM_PATH(fp), lineno);
+           if (multi_line_buf == 0) {
+               saved_member_name = vstring_alloc(100);
+               saved_end_marker = vstring_alloc(100);
+               multi_line_buf = vstring_alloc(100);
+           } else
+               VSTRING_RESET(multi_line_buf);
+           vstring_strcpy(saved_member_name, member_name);
+           vstring_strcpy(saved_end_marker, value);
+           while (vstring_get_nonl(line_buf, fp) > 0) {
+               lineno++;
+               if (strcmp(STR(line_buf), STR(saved_end_marker)) == 0)
+                   break;
+               if (VSTRING_LEN(multi_line_buf) > 0)
+                   vstring_strcat(multi_line_buf, "\n");
+               vstring_strcat(multi_line_buf, STR(line_buf));
+           }
+           if (vstream_feof(fp))
+               msg_fatal("%s, line %d: missing \"%s\" end marker",
+                         VSTREAM_PATH(fp), lineno, value);
+           member_name = STR(saved_member_name);
+           value = STR(multi_line_buf);
+       }
+       dict_update(dict_name, member_name, value);
+    }
+    vstring_free(line_buf);
+    if (multi_line_buf) {
+       vstring_free(saved_member_name);
+       vstring_free(saved_end_marker);
+       vstring_free(multi_line_buf);
+    }
+}
diff --git a/postfix/src/bounce/dict_ml.h b/postfix/src/bounce/dict_ml.h
new file mode 100644 (file)
index 0000000..b7f47dc
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _DICT_ML_H_INCLUDED_
+#define _DICT_ML_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_ml 3h
+/* SUMMARY
+/*     dictionary manager, multi-line entry support
+/* SYNOPSIS
+/*     #include <dict_ml.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+extern void dict_ml_load_file(const char *, const char *);
+extern void dict_ml_load_fp(const char *, VSTREAM *);
+
+/* 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
diff --git a/postfix/src/bounce/fix-template.pl b/postfix/src/bounce/fix-template.pl
new file mode 100644 (file)
index 0000000..5d0dde5
--- /dev/null
@@ -0,0 +1,99 @@
+print <<'EOF'
+#
+# Do not edit this file. This file shows the default delivery status
+# notification (DSN) messages that are built into Postfix.
+#
+# To change Postfix DSN messages, perhaps to add non-English text,
+# follow instructions in the BOUNCE_README document.
+#
+# QUICK INSTRUCTIONS:
+#
+# Copy this file to $config_directory/bounce.cf, edit that file,
+# then specify in main.cf:
+#
+#      bounce_template_file = $config_directory/bounce.cf
+#
+#-The template file can specify bounce message templates for
+# failed mail, delayed mail, successful delivery, and verbose delivery.
+# You don't have to specify templates for all of these. If there is
+# anything about a template that Postfix does not like it logs a
+# warning and keeps using its built-in template.
+#
+#-Each template consists of a few headers and message text. The
+# headers control what the recipient sees as From: and Subject:, and
+# what MIME information Postfix will generate. The message text is
+# not sent in Postmaster copies of delivery status notifications.
+#
+#-You can specify main.cf parameters in a template message text.
+# Some parameters have additional features as described below.
+#
+#-You cannot specify main.cf parameters in template headers.
+#
+#-Each template starts with "template_name = <<EOF" and ends
+# with a line that contains the word "EOF" only. You can change the
+# word EOF if you like, but you can't do shell/perl/etc like things
+# such as enclosing it in quotes (template_name = <<'EOF').
+#
+# IMPORTANT:
+#
+# If you add non-ASCII text then you MUST change the CHARSET: value,
+# otherwise Postfix will not use your template. You must specify a
+# character set that is a superset of US-ASCII, because Postfix
+# appends ASCII text after the message template.
+#
+EOF
+;
+
+while (<>) {
+    if (/^fail_template/) { print <<'EOF'
+
+#
+# The fail template is used when mail is returned to the sender;
+# either the destination rejected the message, or the destination
+# could not be reached before the message expired in the queue.
+#
+
+EOF
+;
+    } elsif (/^delay_template/) { print <<'EOF'
+
+#
+# The delay template is used when mail is delayed. Note a neat trick:
+# the default template displays the delay_warning_time value as hours
+# by appending the _hours suffix to the parameter name; it displays
+# the maximal_queue_lifetime value as days by appending the _days
+# suffix.
+#
+# Other suffixes are: _seconds, _minutes, _weeks. There are no other
+# main.cf parameters that have this special behavior.
+#
+# You need to adjust these suffixes (and the surrounding text) if
+# you have very different settings for these time parameters.
+#
+
+EOF
+;
+    } elsif (/^success_template/) { print <<'EOF'
+
+#
+# The success template is used when mail is delivered to mailbox,
+# when an alias or list is expanded, or when mail is delivered to a
+# system that does not announce DSN support. It is an error to specify
+# a Postmaster-Subject: here.
+#
+
+EOF
+;
+    } elsif (/^verify_template/) { print <<'EOF'
+
+#
+# The verify template is used for address verification (sendmail -bv
+# address...). or for verbose mail delivery (sendmail -v address...).
+# It is an error to specify a Postmaster-Subject: here.
+#
+
+EOF
+;
+    }
+    print $_;
+}
index d7b4f0d8095489357300d44adbd38dcf66be0227..3d9b2da7bd18c694ae23d53034a70a332b983de2 100644 (file)
@@ -207,7 +207,13 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
            state->errs |= CLEANUP_STAT_BAD;
            return;
        }
+
+       /*
+        * XXX This works by accident, because the sender is recorded at the
+        * beginning of the envelope segment.
+        */
        if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0
+           && state->sender && *state->sender
            && var_delay_warn_time > 0) {
            cleanup_out_format(state, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
                               REC_TYPE_WARN_ARG(state->arrival_time.tv_sec
index 6b00c12ea7289874d78338ac474e1e724df162c6..2bb85b0e8f06787326fa9a577ab316e69a9efb7c 100644 (file)
@@ -2397,6 +2397,13 @@ extern bool var_frozen_delivered;
 #define MIN_DELAY_MAX_RES              0
 extern int var_delay_max_res;
 
+ /*
+  * Bounce message templates.
+  */
+#define VAR_BOUNCE_TMPL                        "bounce_template_file"
+#define DEF_BOUNCE_TMPL                        ""
+extern char *var_bounce_tmpl;
+
 /* LICENSE
 /* .ad
 /* .fi
index 4b9d9215ac11f80b7ea23d06b3781ee50ff4677c..2cd5ce343a3f4b34b700845ceef8f9acdde2b017 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20051109"
+#define MAIL_RELEASE_DATE      "20051112"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
index f337b450251c0df4f8fe11721db979c16a2a56f9..182d8eb274d932e40eb247dee1b068e1223d33fe 100644 (file)
@@ -29,7 +29,8 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        unix_recv_fd.c unix_send_fd.c unix_trigger.c unsafe.c uppercase.c \
        username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
        vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
-       write_buf.c write_wait.c sane_basename.c format_tv.c
+       write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
+       allascii.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -60,7 +61,8 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        unix_recv_fd.o unix_send_fd.o unix_trigger.o unsafe.o uppercase.o \
        username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
        vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
-       write_buf.o write_wait.o sane_basename.o format_tv.o
+       write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
+       allascii.o
 HDRS   = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
        dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -532,6 +534,11 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+allascii.o: allascii.c
+allascii.o: stringops.h
+allascii.o: sys_defs.h
+allascii.o: vbuf.h
+allascii.o: vstring.h
 alldig.o: alldig.c
 alldig.o: stringops.h
 alldig.o: sys_defs.h
@@ -542,6 +549,11 @@ allprint.o: stringops.h
 allprint.o: sys_defs.h
 allprint.o: vbuf.h
 allprint.o: vstring.h
+allspace.o: allspace.c
+allspace.o: stringops.h
+allspace.o: sys_defs.h
+allspace.o: vbuf.h
+allspace.o: vstring.h
 argv.o: argv.c
 argv.o: argv.h
 argv.o: msg.h
diff --git a/postfix/src/util/allascii.c b/postfix/src/util/allascii.c
new file mode 100644 (file)
index 0000000..aabbc8e
--- /dev/null
@@ -0,0 +1,50 @@
+/*++
+/* NAME
+/*     allascii 3
+/* SUMMARY
+/*     predicate if string is all ASCII
+/* SYNOPSIS
+/*     #include <stringops.h>
+/*
+/*     int     allascii(buffer)
+/*     const char *buffer;
+/* DESCRIPTION
+/*     allascii() determines if its argument is an all-ASCII string.
+/*
+/*     Arguments:
+/* .IP buffer
+/*     The null-terminated input string.
+/* 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 <ctype.h>
+
+/* Utility library. */
+
+#include "stringops.h"
+
+/* allascii - return true if string is all ASCII */
+
+int     allascii(const char *string)
+{
+    const char *cp;
+    int     ch;
+
+    if (*string == 0)
+       return (0);
+    for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++)
+       if (!ISASCII(ch))
+           return (0);
+    return (1);
+}
diff --git a/postfix/src/util/allspace.c b/postfix/src/util/allspace.c
new file mode 100644 (file)
index 0000000..9a05347
--- /dev/null
@@ -0,0 +1,50 @@
+/*++
+/* NAME
+/*     allspace 3
+/* SUMMARY
+/*     predicate if string is all space
+/* SYNOPSIS
+/*     #include <stringops.h>
+/*
+/*     int     allspace(buffer)
+/*     const char *buffer;
+/* DESCRIPTION
+/*     allspace() determines if its argument is an all-space string.
+/*
+/*     Arguments:
+/* .IP buffer
+/*     The null-terminated input string.
+/* 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 <ctype.h>
+
+/* Utility library. */
+
+#include "stringops.h"
+
+/* allspace - return true if string is all space */
+
+int     allspace(const char *string)
+{
+    const char *cp;
+    int     ch;
+
+    if (*string == 0)
+       return (0);
+    for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++)
+       if (!ISASCII(ch) || !ISSPACE(ch))
+           return (0);
+    return (1);
+}
index d20eb2fd0b1d52726d7b9af214dac3fcee3735cf..e57df6506cfe9bd9b5cd305b3023ad36804a7701 100644 (file)
@@ -55,7 +55,7 @@
 /*
 /*     void    dict_load_fp(dict_name, fp)
 /*     const char *dict_name;
-/*     FILE    *fp;
+/*     VSTREAM *fp;
 /* DESCRIPTION
 /*     This module maintains a collection of name-value dictionaries.
 /*     Each dictionary has its own name and has its own methods to read
index ef06e680422e0741aac708de48e6b7d702ea8ac9..e555cb3c7fa9f5b12081da05374fc3a42309cc70 100644 (file)
@@ -109,7 +109,7 @@ VSTRING *format_tv(VSTRING *buf, int sec, int usec,
     }
 
     /*
-     * Format the number. Truncate thrash below the resolution.
+     * Format the number. Truncate trailing null and thrash below resolution.
      */
     vstring_sprintf_append(buf, "%d", sec);
     if (usec >= ures) {
index 02ea3079a3f485105b94ab8807a4a925f4b282de..04e09df00a55d8abfc42e3643208098a51b2a28f 100644 (file)
@@ -37,6 +37,8 @@ extern char *sane_dirname(VSTRING *, const char *);
 extern VSTRING *unescape(VSTRING *, const char *);
 extern int alldig(const char *);
 extern int allprint(const char *);
+extern int allspace(const char *);
+extern int allascii(const char *);
 extern const char *split_nameval(char *, char **, char **);
 
 /* LICENSE