From efd8a7a29ef229cfab6eef6b57841e259cb581e1 Mon Sep 17 00:00:00 2001
From: Wietse Venema
Date: Sat, 12 Nov 2005 00:00:00 -0500
Subject: [PATCH] postfix-2.3-20051112
---
postfix/.indent.pro | 3 +
postfix/HISTORY | 29 +-
postfix/Makefile.in | 2 +-
postfix/conf/master.cf | 16 +-
postfix/conf/postfix-files | 5 +-
postfix/html/bounce.8.html | 36 +-
postfix/html/postconf.5.html | 11 +
postfix/man/man5/postconf.5 | 4 +
postfix/man/man8/bounce.8 | 2 +
postfix/proto/postconf.proto | 8 +
postfix/src/bounce/Makefile.in | 60 ++-
postfix/src/bounce/bounce.c | 38 ++
postfix/src/bounce/bounce_notify_service.c | 2 +-
postfix/src/bounce/bounce_notify_util.c | 140 ++----
postfix/src/bounce/bounce_notify_verp.c | 2 +-
postfix/src/bounce/bounce_service.h | 71 ++-
postfix/src/bounce/bounce_template.c | 547 +++++++++++++++++++++
postfix/src/bounce/bounce_trace_service.c | 4 +-
postfix/src/bounce/bounce_warn_service.c | 2 +-
postfix/src/bounce/dict_ml.c | 179 +++++++
postfix/src/bounce/dict_ml.h | 37 ++
postfix/src/bounce/fix-template.pl | 99 ++++
postfix/src/cleanup/cleanup_envelope.c | 6 +
postfix/src/global/mail_params.h | 7 +
postfix/src/global/mail_version.h | 2 +-
postfix/src/util/Makefile.in | 16 +-
postfix/src/util/allascii.c | 50 ++
postfix/src/util/allspace.c | 50 ++
postfix/src/util/dict.c | 2 +-
postfix/src/util/format_tv.c | 2 +-
postfix/src/util/stringops.h | 2 +
31 files changed, 1272 insertions(+), 162 deletions(-)
create mode 100644 postfix/src/bounce/bounce_template.c
create mode 100644 postfix/src/bounce/dict_ml.c
create mode 100644 postfix/src/bounce/dict_ml.h
create mode 100644 postfix/src/bounce/fix-template.pl
create mode 100644 postfix/src/util/allascii.c
create mode 100644 postfix/src/util/allspace.c
diff --git a/postfix/.indent.pro b/postfix/.indent.pro
index df2a7dea4..00e85e8cd 100644
--- a/postfix/.indent.pro
+++ b/postfix/.indent.pro
@@ -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
diff --git a/postfix/HISTORY b/postfix/HISTORY
index 82380f622..8c4e6961e 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -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,
diff --git a/postfix/Makefile.in b/postfix/Makefile.in
index fde9ca2a2..6ff54224d 100644
--- a/postfix/Makefile.in
+++ b/postfix/Makefile.in
@@ -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
diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf
index 3833ad6b4..b597e1a37 100644
--- a/postfix/conf/master.cf
+++ b/postfix/conf/master.cf
@@ -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
diff --git a/postfix/conf/postfix-files b/postfix/conf/postfix-files
index 73492dd8d..0ff7c876e 100644
--- a/postfix/conf/postfix-files
+++ b/postfix/conf/postfix-files
@@ -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
diff --git a/postfix/html/bounce.8.html b/postfix/html/bounce.8.html
index 8211f059b..7fa056803 100644
--- a/postfix/html/bounce.8.html
+++ b/postfix/html/bounce.8.html
@@ -78,18 +78,22 @@ BOUNCE(8) BOUNCE(8)
The maximal amount of original message text that is
sent in a non-delivery notification.
+ bounce_template_file (empty)
+ Pathname of a configuration file with bounce mes-
+ sage templates.
+
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
daemon_timeout (18000s)
- 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.
delay_notice_recipient (postmaster)
- 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 $delay_warning_time time units.
deliver_lock_attempts (20)
@@ -97,7 +101,7 @@ BOUNCE(8) BOUNCE(8)
sive lock on a mailbox file or bounce(8) logfile.
deliver_lock_delay (1s)
- The time between attempts to acquire an exclusive
+ The time between attempts to acquire an exclusive
lock on a mailbox file or bounce(8) logfile.
ipc_timeout (3600s)
@@ -110,36 +114,36 @@ BOUNCE(8) BOUNCE(8)
bounced mail.
max_idle (100s)
- 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.
max_use (100)
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
notify_classes (resource, software)
- The list of error classes that are reported to the
+ The list of error classes that are reported to the
postmaster.
process_id (read-only)
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
process_name (read-only)
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
queue_directory (see 'postconf -d' output)
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
syslog_facility (mail)
The syslog facility of Postfix logging.
syslog_name (postfix)
- 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".
FILES
@@ -155,7 +159,7 @@ BOUNCE(8) BOUNCE(8)
syslogd(8), system logging
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index 7bea38b3a..1d721f539 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -1102,6 +1102,17 @@ this limit, then you should increase the bounce_template_file
+(default: empty)
+
+ Pathname of a configuration file with bounce message templates.
+
+
+ This feature is available in Postfix 2.3 and later.
+
+
broken_sasl_auth_clients
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index b1b5b6768..fcc3accaa 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -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
diff --git a/postfix/man/man8/bounce.8 b/postfix/man/man8/bounce.8
index adf9df566..de843697f 100644
--- a/postfix/man/man8/bounce.8
+++ b/postfix/man/man8/bounce.8
@@ -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.
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 802f413b1..80119f197 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -8675,3 +8675,11 @@ precision.
This feature is available in Postfix 2.3 and later.
+
+%PARAM bounce_template_file empty
+
+ Pathname of a configuration file with bounce message templates.
+
+
+ This feature is available in Postfix 2.3 and later.
+
diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in
index f8b0a6e43..f6f3c6141 100644
--- a/postfix/src/bounce/Makefile.in
+++ b/postfix/src/bounce/Makefile.in
@@ -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
diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c
index 14ed9d6ca..de4219a06 100644
--- a/postfix/src/bounce/bounce.c
+++ b/postfix/src/bounce/bounce.c
@@ -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);
diff --git a/postfix/src/bounce/bounce_notify_service.c b/postfix/src/bounce/bounce_notify_service.c
index 1cf6aeb5d..415bdeec4 100644
--- a/postfix/src/bounce/bounce_notify_service.c
+++ b/postfix/src/bounce/bounce_notify_service.c
@@ -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
diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c
index 1b5d70bf3..27a2cd7a0 100644
--- a/postfix/src/bounce/bounce_notify_util.c
+++ b/postfix/src/bounce/bounce_notify_util.c
@@ -13,13 +13,13 @@
/* } 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)
@@ -83,14 +83,11 @@
/* 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");
diff --git a/postfix/src/bounce/bounce_notify_verp.c b/postfix/src/bounce/bounce_notify_verp.c
index 97873bc5f..2c938be8d 100644
--- a/postfix/src/bounce/bounce_notify_verp.c
+++ b/postfix/src/bounce/bounce_notify_verp.c
@@ -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
diff --git a/postfix/src/bounce/bounce_service.h b/postfix/src/bounce/bounce_service.h
index a47fc5db8..e0034c08f 100644
--- a/postfix/src/bounce/bounce_service.h
+++ b/postfix/src/bounce/bounce_service.h
@@ -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
index 000000000..78ccea3a9
--- /dev/null
+++ b/postfix/src/bounce/bounce_template.c
@@ -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
+#include
+#include
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include
+#endif
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Global library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Application-specific. */
+
+#include
+
+ /*
+ * 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
+ * $_days ($_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 = <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);
+}
diff --git a/postfix/src/bounce/bounce_trace_service.c b/postfix/src/bounce/bounce_trace_service.c
index 0212932aa..c760f1618 100644
--- a/postfix/src/bounce/bounce_trace_service.c
+++ b/postfix/src/bounce/bounce_trace_service.c
@@ -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
diff --git a/postfix/src/bounce/bounce_warn_service.c b/postfix/src/bounce/bounce_warn_service.c
index 2a964ceec..229965fd8 100644
--- a/postfix/src/bounce/bounce_warn_service.c
+++ b/postfix/src/bounce/bounce_warn_service.c
@@ -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
index 000000000..d7be3f149
--- /dev/null
+++ b/postfix/src/bounce/dict_ml.c
@@ -0,0 +1,179 @@
+/*++
+/* NAME
+/* dict 3
+/* SUMMARY
+/* dictionary manager, multi-line entry support
+/* SYNOPSIS
+/* #include
+/*
+/* 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 = <
+#include
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
index 000000000..b7f47dc19
--- /dev/null
+++ b/postfix/src/bounce/dict_ml.h
@@ -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
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include
+#include
+
+ /*
+ * 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
index 000000000..5d0dde5ca
--- /dev/null
+++ b/postfix/src/bounce/fix-template.pl
@@ -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 = <) {
+ 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 $_;
+}
diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c
index d7b4f0d80..3d9b2da7b 100644
--- a/postfix/src/cleanup/cleanup_envelope.c
+++ b/postfix/src/cleanup/cleanup_envelope.c
@@ -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
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 6b00c12ea..2bb85b0e8 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -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
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 4b9d9215a..2cd5ce343 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -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
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index f337b4502..182d8eb27 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -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
index 000000000..aabbc8e0d
--- /dev/null
+++ b/postfix/src/util/allascii.c
@@ -0,0 +1,50 @@
+/*++
+/* NAME
+/* allascii 3
+/* SUMMARY
+/* predicate if string is all ASCII
+/* SYNOPSIS
+/* #include
+/*
+/* 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
+#include
+
+/* 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
index 000000000..9a0534712
--- /dev/null
+++ b/postfix/src/util/allspace.c
@@ -0,0 +1,50 @@
+/*++
+/* NAME
+/* allspace 3
+/* SUMMARY
+/* predicate if string is all space
+/* SYNOPSIS
+/* #include
+/*
+/* 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
+#include
+
+/* 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);
+}
diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c
index d20eb2fd0..e57df6506 100644
--- a/postfix/src/util/dict.c
+++ b/postfix/src/util/dict.c
@@ -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
diff --git a/postfix/src/util/format_tv.c b/postfix/src/util/format_tv.c
index ef06e6804..e555cb3c7 100644
--- a/postfix/src/util/format_tv.c
+++ b/postfix/src/util/format_tv.c
@@ -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) {
diff --git a/postfix/src/util/stringops.h b/postfix/src/util/stringops.h
index 02ea3079a..04e09df00 100644
--- a/postfix/src/util/stringops.h
+++ b/postfix/src/util/stringops.h
@@ -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
--
2.47.3