maps_rbl_domains =
diff --git a/postfix/man/man8/nqmgr.8 b/postfix/man/man8/nqmgr.8
index 84a783f40..a343f92a2 100644
--- a/postfix/man/man8/nqmgr.8
+++ b/postfix/man/man8/nqmgr.8
@@ -45,6 +45,9 @@ manager implements exponential backoff by doubling the time between
delivery attempts.
.IP \fBcorrupt\fR
Unreadable or damaged queue files are moved here for inspection.
+.IP \fBhold\fR
+Messages that are kept "on hold" are kept here until someone
+sets them free.
.SH DELIVERY STATUS REPORTS
.na
.nf
@@ -185,6 +188,9 @@ Top-level directory of the Postfix queue.
.fi
In the text below, \fItransport\fR is the first field in a
\fBmaster.cf\fR entry.
+.IP \fBqmgr_clog_warn_time\fR
+Minimal delay between warnings that a specific destination
+is clogging up the active queue. Specify 0 to disable.
.IP \fBqmgr_message_active_limit\fR
Limit the number of messages in the active queue.
.IP \fBqmgr_message_recipient_limit\fR
diff --git a/postfix/man/man8/qmgr.8 b/postfix/man/man8/qmgr.8
index 44b1492c6..f54801953 100644
--- a/postfix/man/man8/qmgr.8
+++ b/postfix/man/man8/qmgr.8
@@ -45,6 +45,9 @@ manager implements exponential backoff by doubling the time between
delivery attempts.
.IP \fBcorrupt\fR
Unreadable or damaged queue files are moved here for inspection.
+.IP \fBhold\fR
+Messages that are kept "on hold" are kept here until someone
+sets them free.
.SH DELIVERY STATUS REPORTS
.na
.nf
@@ -179,6 +182,9 @@ Top-level directory of the Postfix queue.
.SH "Active queue controls"
.ad
.fi
+.IP \fBqmgr_clog_warn_time\fR
+Minimal delay between warnings that a specific destination
+is clogging up the active queue. Specify 0 to disable.
.IP \fBqmgr_message_active_limit\fR
Limit the number of messages in the active queue.
.IP \fBqmgr_message_recipient_limit\fR
@@ -223,15 +229,6 @@ but large mailing list delivery performance suffers. In the worst
case, recipients near the beginning of a large list receive a burst
of messages immediately, while recipients near the end of that list
receive that same burst of messages a whole day later.
-.IP "\fBqmgr_site_hog_factor\fR (valid range: 10..100)"
-The percentage of delivery resources that a busy mail system will
-use up for delivery to a single site.
-With 100%, mail is delivered in first-in, first-out order, so that
-a burst of mail for one site can block mail for other destinations.
-With less than 100%, the excess mail is deferred. The deferred mail
-is delivered in little bursts, the remainder of the backlog being
-deferred again, with a lot of I/O activity happening as Postfix
-searches the deferred queue for deliverable mail.
.IP \fBinitial_destination_concurrency\fR
Initial per-destination concurrency level for parallel delivery
to the same destination.
diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in
index 8eed9c27c..bd8451ea5 100644
--- a/postfix/src/bounce/Makefile.in
+++ b/postfix/src/bounce/Makefile.in
@@ -168,11 +168,10 @@ bounce_one_service.o: ../../include/vstream.h
bounce_one_service.o: ../../include/vbuf.h
bounce_one_service.o: ../../include/name_mask.h
bounce_one_service.o: ../../include/mail_params.h
-bounce_one_service.o: ../../include/mail_queue.h
-bounce_one_service.o: ../../include/vstring.h
bounce_one_service.o: ../../include/post_mail.h
bounce_one_service.o: ../../include/cleanup_user.h
bounce_one_service.o: ../../include/mail_addr.h
bounce_one_service.o: ../../include/mail_error.h
bounce_one_service.o: bounce_service.h
+bounce_one_service.o: ../../include/vstring.h
bounce_one_service.o: ../../include/bounce_log.h
diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in
index 8872993dc..7a7ab688d 100644
--- a/postfix/src/cleanup/Makefile.in
+++ b/postfix/src/cleanup/Makefile.in
@@ -321,6 +321,7 @@ cleanup_message.o: ../../include/iostuff.h
cleanup_message.o: ../../include/attr.h
cleanup_message.o: ../../include/mime_state.h
cleanup_message.o: ../../include/lex_822.h
+cleanup_message.o: ../../include/hold_message.h
cleanup_message.o: cleanup.h
cleanup_message.o: ../../include/maps.h
cleanup_message.o: ../../include/dict.h
diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h
index 389361d42..c795b350f 100644
--- a/postfix/src/cleanup/cleanup.h
+++ b/postfix/src/cleanup/cleanup.h
@@ -35,6 +35,7 @@ typedef struct CLEANUP_STATE {
VSTRING *temp2; /* scratch buffer, local use only */
VSTREAM *dst; /* current output stream */
MAIL_STREAM *handle; /* mail stream handle */
+ char *queue_name; /* queue name */
char *queue_id; /* queue file basename */
time_t time; /* posting time */
char *fullname; /* envelope sender full name */
diff --git a/postfix/src/cleanup/cleanup_api.c b/postfix/src/cleanup/cleanup_api.c
index 80cac48e3..9b6e39b60 100644
--- a/postfix/src/cleanup/cleanup_api.c
+++ b/postfix/src/cleanup/cleanup_api.c
@@ -123,8 +123,12 @@ CLEANUP_STATE *cleanup_open(void)
/*
* Open the queue file. Save the queue file name in a global variable, so
* that the runtime error handler can clean up in case of problems.
+ *
+ * XXX For now, a lot of detail is frozen that could be more useful if it
+ * were made configurable.
*/
- state->handle = mail_stream_file(MAIL_QUEUE_INCOMING,
+ state->queue_name = mystrdup(MAIL_QUEUE_INCOMING);
+ state->handle = mail_stream_file(state->queue_name,
MAIL_CLASS_PUBLIC, var_queue_service, 0);
state->dst = state->handle->stream;
cleanup_path = mystrdup(VSTREAM_PATH(state->dst));
@@ -235,7 +239,7 @@ int cleanup_flush(CLEANUP_STATE *state)
"cleanup", state->time,
"%s", state->reason ? state->reason :
cleanup_strerror(state->errs)) == 0
- && bounce_flush(BOUNCE_FLAG_CLEAN, MAIL_QUEUE_INCOMING,
+ && bounce_flush(BOUNCE_FLAG_CLEAN, state->queue_name,
state->queue_id,
(encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) ?
encoding : MAIL_ATTR_ENC_NONE,
diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c
index e93eb91c9..faa2ab66a 100644
--- a/postfix/src/cleanup/cleanup_message.c
+++ b/postfix/src/cleanup/cleanup_message.c
@@ -80,6 +80,7 @@
#include
#include
#include
+#include
/* Application-specific. */
@@ -313,6 +314,10 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
if (STREQUAL(value, "IGNORE", command_len))
return (CLEANUP_ACT_DROP);
+ if (STREQUAL(value, "HOLD", command_len)) {
+ hold_message(state->queue_name, state->queue_id);
+ return (CLEANUP_ACT_KEEP);
+ }
if (STREQUAL(value, "OK", command_len))
return (CLEANUP_ACT_KEEP);
diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c
index f2944f471..1e7bb8890 100644
--- a/postfix/src/cleanup/cleanup_state.c
+++ b/postfix/src/cleanup/cleanup_state.c
@@ -60,6 +60,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
state->temp2 = vstring_alloc(10);
state->dst = 0;
state->handle = 0;
+ state->queue_name = 0;
state->queue_id = 0;
state->time = 0;
state->fullname = 0;
@@ -115,6 +116,8 @@ void cleanup_state_free(CLEANUP_STATE *state)
myfree(state->errors_to);
argv_free(state->recipients);
argv_free(state->resent_recip);
+ if (state->queue_name)
+ myfree(state->queue_name);
if (state->queue_id)
myfree(state->queue_id);
been_here_free(state->dups);
diff --git a/postfix/src/dns/dns_lookup.c b/postfix/src/dns/dns_lookup.c
index 68a161417..b1a17fba5 100644
--- a/postfix/src/dns/dns_lookup.c
+++ b/postfix/src/dns/dns_lookup.c
@@ -187,6 +187,15 @@ static int dns_query(const char *name, int type, int flags,
if (msg_verbose)
msg_info("dns_query: %s (%s): OK", name, dns_strtype(type));
+ /*
+ * Paranoia.
+ */
+ if (len > sizeof(reply->buf)) {
+ msg_warn("reply length %d > buffer length %d for name=%s type=%s",
+ len, sizeof(reply->buf), name, dns_strtype(type));
+ len = sizeof(reply->buf);
+ }
+
/*
* Initialize the reply structure. Some structure members are filled on
* the fly while the reply is being parsed.
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index 9b3cba78d..ecfabc29e 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -20,7 +20,7 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
verp_sender.c match_parent_style.c mime_state.c header_token.c \
- strip_addr.c virtual8_maps_find.c
+ strip_addr.c virtual8_maps_find.c hold_message.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -42,7 +42,7 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
verp_sender.o match_parent_style.o mime_state.o header_token.o \
- strip_addr.o virtual8_maps_find.o
+ strip_addr.o virtual8_maps_find.o hold_message.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -60,7 +60,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
match_parent_style.h quote_flags.h mime_state.h header_token.h \
- lex_822.h strip_addr.h virtual8.h
+ lex_822.h strip_addr.h virtual8.h hold_message.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -233,7 +233,8 @@ virtual8_maps_find: $(LIB) $(LIBS)
mv junk $@.o
tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
- strip_addr_test tok822_limit_test virtual8_test
+ mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
+ virtual8_test
tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
./tok822_parse tok822_parse.tmp
@@ -265,6 +266,21 @@ mime_trunc: mime_state mime_trunc.in mime_trunc.ref
diff mime_trunc.ref mime_trunc.tmp
rm -f mime_trunc.tmp
+mime_cvt: mime_state mime_cvt.in mime_cvt.ref
+ ./mime_state mime_cvt.tmp
+ diff mime_cvt.ref mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
+mime_cvt2: mime_state mime_cvt.in2 mime_cvt.ref2
+ ./mime_state mime_cvt.tmp
+ diff mime_cvt.ref2 mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
+mime_cvt3: mime_state mime_cvt.in3 mime_cvt.ref3
+ ./mime_state mime_cvt.tmp
+ diff mime_cvt.ref3 mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
tok822_limit_test: tok822_parse tok822_limit.in tok822_limit.ref
./tok822_parse tok822_limit.tmp
diff tok822_limit.ref tok822_limit.tmp
@@ -512,6 +528,16 @@ header_token.o: ../../include/vstring.h
header_token.o: ../../include/vbuf.h
header_token.o: lex_822.h
header_token.o: header_token.h
+hold_message.o: hold_message.c
+hold_message.o: ../../include/sys_defs.h
+hold_message.o: ../../include/msg.h
+hold_message.o: ../../include/set_eugid.h
+hold_message.o: mail_queue.h
+hold_message.o: ../../include/vstring.h
+hold_message.o: ../../include/vbuf.h
+hold_message.o: ../../include/vstream.h
+hold_message.o: mail_params.h
+hold_message.o: hold_message.h
is_header.o: is_header.c
is_header.o: ../../include/sys_defs.h
is_header.o: is_header.h
diff --git a/postfix/src/global/hold_message.c b/postfix/src/global/hold_message.c
new file mode 100644
index 000000000..241a021b2
--- /dev/null
+++ b/postfix/src/global/hold_message.c
@@ -0,0 +1,91 @@
+/*++
+/* NAME
+/* hold_message 3
+/* SUMMARY
+/* move message to hold queue
+/* SYNOPSIS
+/* #include
+/*
+/* void hold_message(queue_name, queue_id)
+/* const char *queue_name;
+/* const char *queue_id;
+/* DESCRIPTION
+/* The \fBhold_message\fR() routine moves the specified
+/* queue file to the \fBhold\fR queue, where it will sit
+/* until someone either destroys it or releases it.
+/* 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 /* rename() */
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+
+/* Global library. */
+
+#include
+#include
+#include
+
+#define STR(x) vstring_str(x)
+
+/* hold_message - move message to hold queue */
+
+void hold_message(const char *queue_name, const char *queue_id)
+{
+ VSTRING *old_path = vstring_alloc(100);
+ VSTRING *new_path = vstring_alloc(100);
+ uid_t saved_uid;
+ gid_t saved_gid;
+
+ /*
+ * If not running as the mail system, change privileges first.
+ */
+ if ((saved_uid = geteuid()) != var_owner_uid) {
+ saved_gid = getegid();
+ set_eugid(var_owner_uid, var_owner_gid);
+ }
+
+ /*
+ * Grr. Don't do stupid things when this function is called multiple
+ * times. sane_rename() would emit a bogus warning about spurious NFS
+ * problems.
+ */
+ (void) mail_queue_path(old_path, queue_name, queue_id);
+ (void) mail_queue_path(new_path, MAIL_QUEUE_HOLD, queue_id);
+ if (access(STR(old_path), F_OK) == 0) {
+ if (rename(STR(old_path), STR(new_path)) == 0
+ || access(STR(new_path), F_OK) == 0)
+ msg_info("%s: placed on hold", queue_id);
+ else
+ msg_warn("%s: could not place message on hold: %m", queue_id);
+ }
+
+ /*
+ * Restore privileges.
+ */
+ if (saved_uid != var_owner_uid)
+ set_eugid(saved_uid, saved_gid);
+
+ /*
+ * Cleanup.
+ */
+ vstring_free(old_path);
+ vstring_free(new_path);
+}
diff --git a/postfix/src/global/hold_message.h b/postfix/src/global/hold_message.h
new file mode 100644
index 000000000..0092c8ca0
--- /dev/null
+++ b/postfix/src/global/hold_message.h
@@ -0,0 +1,30 @@
+#ifndef _HOLD_MESSAGE_H_INCLUDED_
+#define _HOLD_MESSAGE_H_INCLUDED_
+
+/*++
+/* NAME
+/* hold_message 3h
+/* SUMMARY
+/* mark queue file as corrupt
+/* SYNOPSIS
+/* #include
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * External interface.
+ */
+extern void hold_message(const char *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/mail_flush.c b/postfix/src/global/mail_flush.c
index 33f765e87..cfa9c3254 100644
--- a/postfix/src/global/mail_flush.c
+++ b/postfix/src/global/mail_flush.c
@@ -7,11 +7,17 @@
/* #include
/*
/* int mail_flush_deferred()
+/*
+/* int mail_flush_maildrop()
/* DESCRIPTION
/* This module triggers delivery of backed up mail.
/*
/* mail_flush_deferred() triggers delivery of all deferred
-/* or incoming mail.
+/* or incoming mail. This function tickles the queue manager.
+/*
+/* mail_flush_maildrop() triggers delivery of all mail in
+/* the maildrop directory. This function tickles the pickup
+/* service.
/* DIAGNOSTICS
/* The result is 0 in case of success, -1 in case of failure.
/* LICENSE
@@ -37,7 +43,7 @@
#include
#include
-/* mail_flush_deferred - flush deferred queue */
+/* mail_flush_deferred - flush deferred/incoming queue */
int mail_flush_deferred(void)
{
@@ -54,3 +60,16 @@ int mail_flush_deferred(void)
return (mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service,
qmgr_trigger, sizeof(qmgr_trigger)));
}
+
+/* mail_flush_maildrop - flush maildrop queue */
+
+int mail_flush_maildrop(void)
+{
+ static char wakeup[] = {TRIGGER_REQ_WAKEUP};
+
+ /*
+ * Trigger the pickup service.
+ */
+ return (mail_trigger(MAIL_CLASS_PUBLIC, var_pickup_service,
+ wakeup, sizeof(wakeup)));
+}
diff --git a/postfix/src/global/mail_flush.h b/postfix/src/global/mail_flush.h
index 9d951682f..03f3945f6 100644
--- a/postfix/src/global/mail_flush.h
+++ b/postfix/src/global/mail_flush.h
@@ -14,6 +14,7 @@
/* External interface. */
extern int mail_flush_deferred(void);
+extern int mail_flush_maildrop(void);
/* LICENSE
/* .ad
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 7c6cce559..eeb44f325 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -542,10 +542,6 @@ extern int var_min_delivery_slots;
#define DEF_QMGR_FUDGE 100
extern int var_qmgr_fudge;
-#define VAR_QMGR_HOG "qmgr_site_hog_factor"
-#define DEF_QMGR_HOG 100
-extern int var_qmgr_hog;
-
/*
* Queue manager: default destination concurrency levels.
*/
@@ -588,6 +584,14 @@ extern int var_transport_retry_time;
#define DEF_DEFER_XPORTS ""
extern char *var_defer_xports;
+ /*
+ * Queue manager: how often to warn that a destination is clogging the
+ * active queue.
+ */
+#define VAR_QMGR_CLOG_WARN_TIME "qmgr_clog_warn_time"
+#define DEF_QMGR_CLOG_WARN_TIME "300s"
+extern int var_qmgr_clog_warn_time;
+
/*
* Master: default process count limit per mail subsystem.
*/
diff --git a/postfix/src/global/mail_stream.c b/postfix/src/global/mail_stream.c
index 74a8ada8c..6e4812e03 100644
--- a/postfix/src/global/mail_stream.c
+++ b/postfix/src/global/mail_stream.c
@@ -133,10 +133,10 @@ static int mail_stream_finish_file(MAIL_STREAM * info, VSTRING *unused_why)
* take effect before all the data blocks are written. Wietse claims that
* this is not a problem. Postfix rejects incomplete queue files, even
* when the +x attribute is set. Every Postfix queue file record has a
- * type code and a length field. Files with truncated records are
- * rejected, as are files with unknown type codes. Every Postfix queue
- * file must end with an explicit END record. Postfix queue files without
- * END record are discarded.
+ * type code and a length field. Files with missing records are rejected,
+ * as are files with unknown record type codes. Every Postfix queue file
+ * must end with an explicit END record. Postfix queue files without END
+ * record are discarded.
*/
if (vstream_fflush(info->stream)
|| fchmod(vstream_fileno(info->stream), 0700 | info->mode)
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 74542bfe1..a3f5d3564 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20020804"
+#define MAIL_RELEASE_DATE "20020819"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE
diff --git a/postfix/src/global/mime_8bit.ref b/postfix/src/global/mime_8bit.ref
index 0e70ac9b3..e9d6eae09 100644
--- a/postfix/src/global/mime_8bit.ref
+++ b/postfix/src/global/mime_8bit.ref
@@ -1,9 +1,9 @@
mime_state: warning: improper use of 8-bit data in message header: Header: f??bar
MAIN Header: f€€bar
HEADER END
-BODY
+BODY N
mime_state: warning: improper use of 8-bit data in message body: b?dy
-BODY b€dy
+BODY N b€dy
BODY END
mime_state: warning: improper use of 8-bit data in message header
mime_state: warning: improper use of 8-bit data in message body
diff --git a/postfix/src/global/mime_cvt.in b/postfix/src/global/mime_cvt.in
new file mode 100644
index 000000000..f3b73217b
--- /dev/null
+++ b/postfix/src/global/mime_cvt.in
@@ -0,0 +1,83 @@
+mime-version: 1.0
+content-type: text/plain
+content-transfer-encoding: 8bit
+
+
+x
+xx
+xxx
+xxxx
+xxxxx
+xxxxxx
+xxxxxxx
+xxxxxxxx
+xxxxxxxxx
+xxxxxxxxxx
+xxxxxxxxxxx
+xxxxxxxxxxxx
+xxxxxxxxxxxxx
+xxxxxxxxxxxxxx
+xxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/postfix/src/global/mime_cvt.in2 b/postfix/src/global/mime_cvt.in2
new file mode 100644
index 000000000..c7b35ae97
--- /dev/null
+++ b/postfix/src/global/mime_cvt.in2
@@ -0,0 +1,83 @@
+mime-version: 1.0
+content-type: text/plain
+content-transfer-encoding: 8bit
+
+
+x
+xx
+xxx
+xxxx
+xxxxx
+xxxxxx
+xxxxxxx
+xxxxxxxx
+xxxxxxxxx
+xxxxxxxxxx
+xxxxxxxxxxx
+xxxxxxxxxxxx
+xxxxxxxxxxxxx
+xxxxxxxxxxxxxx
+xxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/postfix/src/global/mime_cvt.in3 b/postfix/src/global/mime_cvt.in3
new file mode 100644
index 000000000..31621b6c2
--- /dev/null
+++ b/postfix/src/global/mime_cvt.in3
@@ -0,0 +1,83 @@
+mime-version: 1.0
+content-type: text/plain
+content-transfer-encoding: 8bit
+
+
+x
+xx
+xxx
+xxxx
+xxxxx
+xxxxxx
+xxxxxxx
+xxxxxxxx
+xxxxxxxxx
+xxxxxxxxxx
+xxxxxxxxxxx
+xxxxxxxxxxxx
+xxxxxxxxxxxxx
+xxxxxxxxxxxxxx
+xxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/postfix/src/global/mime_cvt.ref b/postfix/src/global/mime_cvt.ref
new file mode 100644
index 000000000..a6e0227c2
--- /dev/null
+++ b/postfix/src/global/mime_cvt.ref
@@ -0,0 +1,93 @@
+MAIN mime-version: 1.0
+mime_state: header_token: text / plain
+MAIN content-type: text/plain
+mime_state: header_token: 8bit
+MAIN Content-Transfer-Encoding: quoted-printable
+HEADER END
+BODY N
+BODY N =20
+BODY N x=20
+BODY N xx=20
+BODY N xxx=20
+BODY N xxxx=20
+BODY N xxxxx=20
+BODY N xxxxxx=20
+BODY N xxxxxxx=20
+BODY N xxxxxxxx=20
+BODY N xxxxxxxxx=20
+BODY N xxxxxxxxxx=20
+BODY N xxxxxxxxxxx=20
+BODY N xxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N =20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N x=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxx=20
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxxx=20
+BODY END
diff --git a/postfix/src/global/mime_cvt.ref2 b/postfix/src/global/mime_cvt.ref2
new file mode 100644
index 000000000..fa0d00a43
--- /dev/null
+++ b/postfix/src/global/mime_cvt.ref2
@@ -0,0 +1,93 @@
+MAIN mime-version: 1.0
+mime_state: header_token: text / plain
+MAIN content-type: text/plain
+mime_state: header_token: 8bit
+MAIN Content-Transfer-Encoding: quoted-printable
+HEADER END
+BODY N
+BODY N =09
+BODY N x=09
+BODY N xx=09
+BODY N xxx=09
+BODY N xxxx=09
+BODY N xxxxx=09
+BODY N xxxxxx=09
+BODY N xxxxxxx=09
+BODY N xxxxxxxx=09
+BODY N xxxxxxxxx=09
+BODY N xxxxxxxxxx=09
+BODY N xxxxxxxxxxx=09
+BODY N xxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N =09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N x=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxx=09
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxxx=09
+BODY END
diff --git a/postfix/src/global/mime_cvt.ref3 b/postfix/src/global/mime_cvt.ref3
new file mode 100644
index 000000000..a5b4f64d8
--- /dev/null
+++ b/postfix/src/global/mime_cvt.ref3
@@ -0,0 +1,93 @@
+MAIN mime-version: 1.0
+mime_state: header_token: text / plain
+MAIN content-type: text/plain
+mime_state: header_token: 8bit
+MAIN Content-Transfer-Encoding: quoted-printable
+HEADER END
+BODY N
+BODY N =01
+BODY N x=01
+BODY N xx=01
+BODY N xxx=01
+BODY N xxxx=01
+BODY N xxxxx=01
+BODY N xxxxxx=01
+BODY N xxxxxxx=01
+BODY N xxxxxxxx=01
+BODY N xxxxxxxxx=01
+BODY N xxxxxxxxxx=01
+BODY N xxxxxxxxxxx=01
+BODY N xxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N =01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N x=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxx=01
+BODY N xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+BODY N xxxxx=01
+BODY END
diff --git a/postfix/src/global/mime_nest.ref b/postfix/src/global/mime_nest.ref
index dd1a92fdd..d1e32cb37 100644
--- a/postfix/src/global/mime_nest.ref
+++ b/postfix/src/global/mime_nest.ref
@@ -3,140 +3,140 @@ mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MAIN content-type: multipart/mixed; boundary=foobar
HEADER END
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: warning: MIME nesting exceeds safety limit: content-type: multipart/mixed; boundary=foobar
MULT content-type: multipart/mixed; boundary=foobar
-BODY
-BODY --foobar
+BODY N
+BODY N --foobar
BODY END
mime_state: warning: MIME nesting exceeds safety limit
mime_state: POP boundary foobar
diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c
index badec42f6..b5cf003fa 100644
--- a/postfix/src/global/mime_state.c
+++ b/postfix/src/global/mime_state.c
@@ -618,12 +618,12 @@ static void mime_state_downgrade(MIME_STATE *state, int rec_type,
{
static char hexchars[] = "0123456789ABCDEF";
const unsigned char *cp;
- int ch = 0;
+ int ch;
-#define QP_ENCODE(state, ch) { \
- VSTRING_ADDCH(state->output_buffer, '='); \
- VSTRING_ADDCH(state->output_buffer, hexchars[(ch >> 4) & 0xff]); \
- VSTRING_ADDCH(state->output_buffer, hexchars[ch & 0xf]); \
+#define QP_ENCODE(buffer, ch) { \
+ VSTRING_ADDCH(buffer, '='); \
+ VSTRING_ADDCH(buffer, hexchars[(ch >> 4) & 0xff]); \
+ VSTRING_ADDCH(buffer, hexchars[ch & 0xf]); \
}
/*
@@ -634,6 +634,7 @@ static void mime_state_downgrade(MIME_STATE *state, int rec_type,
/* Critical length before hard line break. */
if (LEN(state->output_buffer) > 72) {
VSTRING_ADDCH(state->output_buffer, '=');
+ VSTRING_TERMINATE(state->output_buffer);
state->body_out(state->app_context, REC_TYPE_NORM,
STR(state->output_buffer),
LEN(state->output_buffer));
@@ -642,7 +643,7 @@ static void mime_state_downgrade(MIME_STATE *state, int rec_type,
/* Append the next character. */
ch = *cp;
if ((ch < 32 && ch != '\t') || ch == '=' || ch > 126) {
- QP_ENCODE(state, ch);
+ QP_ENCODE(state->output_buffer, ch);
} else {
VSTRING_ADDCH(state->output_buffer, ch);
}
@@ -654,13 +655,13 @@ static void mime_state_downgrade(MIME_STATE *state, int rec_type,
* the output length will grow from 73 characters to 75 characters.
*/
if (rec_type == REC_TYPE_NORM) {
- if (ch == 0 && LEN(state->output_buffer) > 0)
- ch = END(state->output_buffer)[-1];
- if (ch == ' ' || ch == '\t') {
+ if (LEN(state->output_buffer) > 0
+ && ((ch = END(state->output_buffer)[-1]) == ' ' || ch == '\t')) {
vstring_truncate(state->output_buffer,
LEN(state->output_buffer) - 1);
- QP_ENCODE(state, ch);
+ QP_ENCODE(state->output_buffer, ch);
}
+ VSTRING_TERMINATE(state->output_buffer);
state->body_out(state->app_context, REC_TYPE_NORM,
STR(state->output_buffer),
LEN(state->output_buffer));
@@ -1034,7 +1035,7 @@ static void body_out(void *context, int rec_type, const char *buf, int len)
{
VSTREAM *stream = (VSTREAM *) context;
- vstream_fprintf(stream, "BODY\t");
+ vstream_fprintf(stream, "BODY %c\t", rec_type);
vstream_fwrite(stream, buf, len);
if (rec_type == REC_TYPE_NORM)
VSTREAM_PUTC('\n', stream);
diff --git a/postfix/src/global/mime_test.ref b/postfix/src/global/mime_test.ref
index 614574ff0..ef36f7810 100644
--- a/postfix/src/global/mime_test.ref
+++ b/postfix/src/global/mime_test.ref
@@ -5,13 +5,13 @@ mime_state: PUSH boundary abcd ef
MAIN content-type: multipart/(co\m\)ment)mumble mumble; boundary = "ab\cd
ef" mumble
HEADER END
-BODY
-BODY abcdef prolog
-BODY
-BODY --abcd ef
+BODY N
+BODY N abcdef prolog
+BODY N
+BODY N --abcd ef
mime_state: header_token: message / rfc822
MULT content-type: message/rfc822; mumble
-BODY
+BODY N
NEST subject: nested subject
mime_state: header_token: multipart / mumble
mime_state: header_token: boundary = pqrs
@@ -20,33 +20,33 @@ NEST content-type: multipart/mumble; boundary(comment)="pqrs"
mime_state: header_token: base64
NEST content-transfer-encoding: base64
mime_state: warning: invalid message/* or multipart/* encoding domain: base64
-BODY
-BODY pqrs prolog
-BODY
-BODY --pqrs
+BODY N
+BODY N pqrs prolog
+BODY N
+BODY N --pqrs
MULT header: pqrs part 01
-BODY
-BODY body pqrs part 01
-BODY
-BODY --pqrs
+BODY N
+BODY N body pqrs part 01
+BODY N
+BODY N --pqrs
MULT header: pqrs part 02
-BODY
-BODY body pqrs part 02
-BODY
-BODY --bogus-boundary
-BODY header: wietse
-BODY
-BODY body asdasads
-BODY
+BODY N
+BODY N body pqrs part 02
+BODY N
+BODY N --bogus-boundary
+BODY N header: wietse
+BODY N
+BODY N body asdasads
+BODY N
mime_state: POP boundary pqrs
-BODY --abcd ef
+BODY N --abcd ef
MULT header: abcdef part 02
-BODY
-BODY body abcdef part 02
-BODY
+BODY N
+BODY N body abcdef part 02
+BODY N
mime_state: POP boundary abcd ef
-BODY --abcd ef--
-BODY
-BODY epilog
+BODY N --abcd ef--
+BODY N
+BODY N epilog
BODY END
mime_state: warning: improper message/* or multipart/* encoding domain
diff --git a/postfix/src/nqmgr/qmgr.c b/postfix/src/nqmgr/qmgr.c
index 7da725d3d..57f65cac4 100644
--- a/postfix/src/nqmgr/qmgr.c
+++ b/postfix/src/nqmgr/qmgr.c
@@ -37,6 +37,9 @@
/* delivery attempts.
/* .IP \fBcorrupt\fR
/* Unreadable or damaged queue files are moved here for inspection.
+/* .IP \fBhold\fR
+/* Messages that are kept "on hold" are kept here until someone
+/* sets them free.
/* DELIVERY STATUS REPORTS
/* .ad
/* .fi
@@ -161,6 +164,9 @@
/* .fi
/* In the text below, \fItransport\fR is the first field in a
/* \fBmaster.cf\fR entry.
+/* .IP \fBqmgr_clog_warn_time\fR
+/* Minimal delay between warnings that a specific destination
+/* is clogging up the active queue. Specify 0 to disable.
/* .IP \fBqmgr_message_active_limit\fR
/* Limit the number of messages in the active queue.
/* .IP \fBqmgr_message_recipient_limit\fR
@@ -338,6 +344,7 @@ int var_local_rcpt_lim;
int var_proc_limit;
bool var_verp_bounce_off;
bool var_sender_routing;
+int var_qmgr_clog_warn_time;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
@@ -502,6 +509,15 @@ static void qmgr_pre_init(char *unused_name, char **unused_argv)
static void qmgr_post_init(char *unused_name, char **unused_argv)
{
+ /*
+ * Sanity check.
+ */
+ if (var_qmgr_rcpt_limit < var_qmgr_active_limit) {
+ msg_warn("%s is smaller than %s",
+ VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT);
+ var_qmgr_rcpt_limit = var_qmgr_active_limit;
+ }
+
/*
* This routine runs after the skeleton code has entered the chroot jail.
* Prevent automatic process suicide after a limited number of client
@@ -539,6 +555,7 @@ int main(int argc, char **argv)
VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000,
VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
+ VAR_QMGR_CLOG_WARN_TIME, DEF_QMGR_CLOG_WARN_TIME, &var_qmgr_clog_warn_time, 0, 0,
0,
};
static CONFIG_INT_TABLE int_table[] = {
diff --git a/postfix/src/nqmgr/qmgr.h b/postfix/src/nqmgr/qmgr.h
index 9607268f6..16505f6e4 100644
--- a/postfix/src/nqmgr/qmgr.h
+++ b/postfix/src/nqmgr/qmgr.h
@@ -190,6 +190,7 @@ struct QMGR_QUEUE {
QMGR_ENTRY_LIST busy; /* messages on the wire */
QMGR_QUEUE_LIST peers; /* neighbor queues */
char *reason; /* why unavailable */
+ time_t clog_time_to_warn; /* time of last warning */
int blocker_tag; /* tagged if blocks job list */
};
diff --git a/postfix/src/nqmgr/qmgr_entry.c b/postfix/src/nqmgr/qmgr_entry.c
index 64cec0b28..e1e733f2a 100644
--- a/postfix/src/nqmgr/qmgr_entry.c
+++ b/postfix/src/nqmgr/qmgr_entry.c
@@ -253,6 +253,9 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
if (queue->window == 0)
msg_panic("qmgr_entry_create: dead queue: %s", queue->name);
+ /*
+ * Create the delivery request.
+ */
entry = (QMGR_ENTRY *) mymalloc(sizeof(QMGR_ENTRY));
entry->stream = 0;
entry->message = message;
@@ -264,5 +267,61 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
entry->queue = queue;
QMGR_LIST_APPEND(queue->todo, entry, queue_peers);
queue->todo_refcount++;
+
+ /*
+ * Warn if a destination is falling behind while the active queue
+ * contains a non-trivial amount of single-recipient email. When a
+ * destination takes up more and more space in the active queue, then
+ * other mail will not get through and delivery performance will suffer.
+ *
+ * XXX At this point in the code, the busy reference count is still less
+ * than the concurrency limit (otherwise this code would not be invoked
+ * in the first place) so we have to make make some awkward adjustments
+ * below.
+ *
+ * XXX The queue length test below looks at the active queue share of an
+ * individual destination. This catches the case where mail for one
+ * destination is falling behind because it has to round-robin compete
+ * with many other destinations. However, Postfix will also perform
+ * poorly when most of the active queue is tied up by a small number of
+ * concurrency limited destinations. The queue length test below detects
+ * such conditions only indirectly.
+ *
+ * XXX This code does not detect the case that the active queue is being
+ * starved because incoming mail is pounding the disk.
+ */
+ if (var_qmgr_clog_warn_time > 0) {
+ int queue_length = queue->todo_refcount + queue->busy_refcount;
+ time_t now;
+ QMGR_TRANSPORT *transport;
+ double active_share;
+
+ if (queue_length > var_qmgr_active_limit / 5
+ && (now = event_time()) >= queue->clog_time_to_warn) {
+ active_share = queue_length / (double) qmgr_message_count;
+ msg_warn("mail for %s is using up %d of %d active queue entries",
+ queue->name, queue_length, qmgr_message_count);
+ if (active_share < 0.9)
+ msg_warn("this may slow down other mail deliveries");
+ transport = queue->transport;
+ if (transport->dest_concurrency_limit > 0
+ && transport->dest_concurrency_limit <= queue->busy_refcount + 1)
+ msg_warn("you may need to increase the main.cf %s%s from %d",
+ transport->name, _DEST_CON_LIMIT,
+ transport->dest_concurrency_limit);
+ else if (queue->window > var_qmgr_active_limit * active_share)
+ msg_warn("you may need to increase the main.cf %s from %d",
+ VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
+ else if (queue->peers.next != queue->peers.prev)
+ msg_warn("you may need a separate master.cf transport for %s",
+ queue->name);
+ else if (transport->dest_concurrency_limit / 2 > queue->busy_refcount)
+ msg_warn("you may need to increase the master.cf %s process limit",
+ transport->name);
+ msg_warn("to turn off these warnings specify: %s = 0",
+ VAR_QMGR_CLOG_WARN_TIME);
+ queue->clog_time_to_warn = now + var_qmgr_clog_warn_time;
+ }
+ }
return (entry);
}
diff --git a/postfix/src/nqmgr/qmgr_queue.c b/postfix/src/nqmgr/qmgr_queue.c
index d4aced58e..9854011b6 100644
--- a/postfix/src/nqmgr/qmgr_queue.c
+++ b/postfix/src/nqmgr/qmgr_queue.c
@@ -237,6 +237,7 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
QMGR_LIST_INIT(queue->todo);
QMGR_LIST_INIT(queue->busy);
queue->reason = 0;
+ queue->clog_time_to_warn = 0;
queue->blocker_tag = 0;
QMGR_LIST_APPEND(transport->queue_list, queue, peers);
htable_enter(transport->queue_byname, site, (char *) queue);
diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c
index e50c72117..9b3dba8d3 100644
--- a/postfix/src/pickup/pickup.c
+++ b/postfix/src/pickup/pickup.c
@@ -381,6 +381,9 @@ static int pickup_file(PICKUP_INFO *info)
if (errno != ENOENT)
msg_warn("open input file %s: %s", info->path, vstring_str(buf));
vstring_free(buf);
+ if (errno == EACCES)
+ msg_warn("if this file was created by Postfix < 1.1, then you may have to chmod a+r %s/%s",
+ var_queue_dir, info->path);
return (errno == EACCES ? KEEP_MESSAGE_FILE : REMOVE_MESSAGE_FILE);
}
diff --git a/postfix/src/postcat/postcat.c b/postfix/src/postcat/postcat.c
index dc76c8a09..824c95422 100644
--- a/postfix/src/postcat/postcat.c
+++ b/postfix/src/postcat/postcat.c
@@ -106,10 +106,16 @@ static void postcat(VSTREAM *fp, VSTRING *buffer)
vstream_printf("defer_warn_time: %s", asctime(localtime(&time)));
break;
case REC_TYPE_CONT:
- vstream_printf("%s", STR(buffer));
+ if (msg_verbose)
+ vstream_printf("non-final line fragment: %s\n", STR(buffer));
+ else
+ vstream_printf("%s", STR(buffer));
break;
case REC_TYPE_NORM:
- vstream_printf("%s\n", STR(buffer));
+ if (msg_verbose)
+ vstream_printf("final line fragment: %s\n", STR(buffer));
+ else
+ vstream_printf("%s\n", STR(buffer));
break;
case REC_TYPE_MESG:
vstream_printf("*** MESSAGE CONTENTS %s ***\n", VSTREAM_PATH(fp));
diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c
index ad8a159b7..41b15b44c 100644
--- a/postfix/src/postqueue/postqueue.c
+++ b/postfix/src/postqueue/postqueue.c
@@ -249,6 +249,9 @@ static void flush_queue(void)
if (mail_flush_deferred() < 0)
msg_fatal_status(EX_UNAVAILABLE,
"Cannot flush mail queue - mail system is down");
+ if (mail_flush_maildrop() < 0)
+ msg_fatal_status(EX_UNAVAILABLE,
+ "Cannot flush mail queue - mail system is down");
}
/* flush_site - flush mail for site */
diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c
index 963532059..87d75dd82 100644
--- a/postfix/src/qmgr/qmgr.c
+++ b/postfix/src/qmgr/qmgr.c
@@ -37,6 +37,9 @@
/* delivery attempts.
/* .IP \fBcorrupt\fR
/* Unreadable or damaged queue files are moved here for inspection.
+/* .IP \fBhold\fR
+/* Messages that are kept "on hold" are kept here until someone
+/* sets them free.
/* DELIVERY STATUS REPORTS
/* .ad
/* .fi
@@ -155,6 +158,9 @@
/* .SH "Active queue controls"
/* .ad
/* .fi
+/* .IP \fBqmgr_clog_warn_time\fR
+/* Minimal delay between warnings that a specific destination
+/* is clogging up the active queue. Specify 0 to disable.
/* .IP \fBqmgr_message_active_limit\fR
/* Limit the number of messages in the active queue.
/* .IP \fBqmgr_message_recipient_limit\fR
@@ -199,15 +205,6 @@
/* case, recipients near the beginning of a large list receive a burst
/* of messages immediately, while recipients near the end of that list
/* receive that same burst of messages a whole day later.
-/* .IP "\fBqmgr_site_hog_factor\fR (valid range: 10..100)"
-/* The percentage of delivery resources that a busy mail system will
-/* use up for delivery to a single site.
-/* With 100%, mail is delivered in first-in, first-out order, so that
-/* a burst of mail for one site can block mail for other destinations.
-/* With less than 100%, the excess mail is deferred. The deferred mail
-/* is delivered in little bursts, the remainder of the backlog being
-/* deferred again, with a lot of I/O activity happening as Postfix
-/* searches the deferred queue for deliverable mail.
/* .IP \fBinitial_destination_concurrency\fR
/* Initial per-destination concurrency level for parallel delivery
/* to the same destination.
@@ -291,12 +288,12 @@ char *var_virtual_maps;
char *var_defer_xports;
bool var_allow_min_user;
int var_qmgr_fudge;
-int var_qmgr_hog;
int var_local_rcpt_lim; /* XXX */
int var_local_con_lim; /* XXX */
int var_proc_limit;
bool var_verp_bounce_off;
bool var_sender_routing;
+int var_qmgr_clog_warn_time;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
@@ -464,6 +461,15 @@ static void qmgr_pre_init(char *unused_name, char **unused_argv)
static void qmgr_post_init(char *unused_name, char **unused_argv)
{
+ /*
+ * Sanity check.
+ */
+ if (var_qmgr_rcpt_limit < var_qmgr_active_limit) {
+ msg_warn("%s is smaller than %s",
+ VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT);
+ var_qmgr_rcpt_limit = var_qmgr_active_limit;
+ }
+
/*
* This routine runs after the skeleton code has entered the chroot jail.
* Prevent automatic process suicide after a limited number of client
@@ -501,6 +507,7 @@ int main(int argc, char **argv)
VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000,
VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
+ VAR_QMGR_CLOG_WARN_TIME, DEF_QMGR_CLOG_WARN_TIME, &var_qmgr_clog_warn_time, 0, 0,
0,
};
static CONFIG_INT_TABLE int_table[] = {
@@ -510,7 +517,6 @@ int main(int argc, char **argv)
VAR_DEST_CON_LIMIT, DEF_DEST_CON_LIMIT, &var_dest_con_limit, 0, 0,
VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0,
VAR_QMGR_FUDGE, DEF_QMGR_FUDGE, &var_qmgr_fudge, 10, 100,
- VAR_QMGR_HOG, DEF_QMGR_HOG, &var_qmgr_hog, 10, 100,
VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0,
VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h
index 4f15f8c90..6f01c4f32 100644
--- a/postfix/src/qmgr/qmgr.h
+++ b/postfix/src/qmgr/qmgr.h
@@ -154,6 +154,7 @@ struct QMGR_QUEUE {
QMGR_ENTRY_LIST busy; /* messages on the wire */
QMGR_QUEUE_LIST peers; /* neighbor queues */
char *reason; /* why unavailable */
+ time_t clog_time_to_warn; /* time of next warning */
};
#define QMGR_QUEUE_TODO 1 /* waiting for service */
diff --git a/postfix/src/qmgr/qmgr_entry.c b/postfix/src/qmgr/qmgr_entry.c
index 1d5c3afac..7a5f9dfdb 100644
--- a/postfix/src/qmgr/qmgr_entry.c
+++ b/postfix/src/qmgr/qmgr_entry.c
@@ -195,6 +195,9 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *queue, QMGR_MESSAGE *message)
if (queue->window == 0)
msg_panic("qmgr_entry_create: dead queue: %s", queue->name);
+ /*
+ * Create the delivery request.
+ */
entry = (QMGR_ENTRY *) mymalloc(sizeof(QMGR_ENTRY));
entry->stream = 0;
entry->message = message;
@@ -203,5 +206,61 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *queue, QMGR_MESSAGE *message)
entry->queue = queue;
QMGR_LIST_APPEND(queue->todo, entry);
queue->todo_refcount++;
+
+ /*
+ * Warn if a destination is falling behind while the active queue
+ * contains a non-trivial amount of single-recipient email. When a
+ * destination takes up more and more space in the active queue, then
+ * other mail will not get through and delivery performance will suffer.
+ *
+ * XXX At this point in the code, the busy reference count is still less
+ * than the concurrency limit (otherwise this code would not be invoked
+ * in the first place) so we have to make make some awkward adjustments
+ * below.
+ *
+ * XXX The queue length test below looks at the active queue share of an
+ * individual destination. This catches the case where mail for one
+ * destination is falling behind because it has to round-robin compete
+ * with many other destinations. However, Postfix will also perform
+ * poorly when most of the active queue is tied up by a small number of
+ * concurrency limited destinations. The queue length test below detects
+ * such conditions only indirectly.
+ *
+ * XXX This code does not detect the case that the active queue is being
+ * starved because incoming mail is pounding the disk.
+ */
+ if (var_qmgr_clog_warn_time > 0) {
+ int queue_length = queue->todo_refcount + queue->busy_refcount;
+ time_t now;
+ QMGR_TRANSPORT *transport;
+ double active_share;
+
+ if (queue_length > var_qmgr_active_limit / 5
+ && (now = event_time()) >= queue->clog_time_to_warn) {
+ active_share = queue_length / (double) qmgr_message_count;
+ msg_warn("mail for %s is using up %d of %d active queue entries",
+ queue->name, queue_length, qmgr_message_count);
+ if (active_share < 0.9)
+ msg_warn("this may slow down other mail deliveries");
+ transport = queue->transport;
+ if (transport->dest_concurrency_limit > 0
+ && transport->dest_concurrency_limit <= queue->busy_refcount + 1)
+ msg_warn("you may need to increase the main.cf %s%s from %d",
+ transport->name, _DEST_CON_LIMIT,
+ transport->dest_concurrency_limit);
+ else if (queue->window > var_qmgr_active_limit * active_share)
+ msg_warn("you may need to increase the main.cf %s from %d",
+ VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
+ else if (queue->peers.next != queue->peers.prev)
+ msg_warn("you may need a separate master.cf transport for %s",
+ queue->name);
+ else if (transport->dest_concurrency_limit / 2 > queue->busy_refcount)
+ msg_warn("you may need to increase the master.cf %s process limit",
+ transport->name);
+ msg_warn("to turn off these warnings specify: %s = 0",
+ VAR_QMGR_CLOG_WARN_TIME);
+ queue->clog_time_to_warn = now + var_qmgr_clog_warn_time;
+ }
+ }
return (entry);
}
diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c
index 9bbac6975..9eb702376 100644
--- a/postfix/src/qmgr/qmgr_message.c
+++ b/postfix/src/qmgr/qmgr_message.c
@@ -722,23 +722,6 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
continue;
}
- /*
- * This queue is a hog. Defer this recipient until the queue drains.
- * When a site accumulates a large backlog, Postfix will deliver a
- * little chunk and hammer the disk as it defers the remainder of the
- * backlog and searches the deferred queue for deliverable mail.
- */
- if (var_qmgr_hog < 100) {
- if (queue->todo_refcount + queue->busy_refcount
- > (var_qmgr_hog / 100.0)
- * (qmgr_recipient_count > 0.8 * var_qmgr_rcpt_limit ?
- qmgr_message_count : var_qmgr_active_limit)) {
- qmgr_defer_recipient(message, recipient->address,
- "site destination queue overflow");
- continue;
- }
- }
-
/*
* This queue is alive. Bind this recipient to this queue instance.
*/
diff --git a/postfix/src/qmgr/qmgr_queue.c b/postfix/src/qmgr/qmgr_queue.c
index 8b38d4462..7d4214f70 100644
--- a/postfix/src/qmgr/qmgr_queue.c
+++ b/postfix/src/qmgr/qmgr_queue.c
@@ -260,6 +260,7 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
QMGR_LIST_INIT(queue->todo);
QMGR_LIST_INIT(queue->busy);
queue->reason = 0;
+ queue->clog_time_to_warn = 0;
QMGR_LIST_PREPEND(transport->queue_list, queue);
htable_enter(transport->queue_byname, site, (char *) queue);
return (queue);
diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c
index c402bc4ad..1b3215110 100644
--- a/postfix/src/smtp/smtp_proto.c
+++ b/postfix/src/smtp/smtp_proto.c
@@ -305,7 +305,8 @@ static void smtp_text_out(void *context, int rec_type,
data_left = len;
data_start = text;
do {
- if (state->space_left == var_smtp_line_limit && *data_start == '.')
+ if (state->space_left == var_smtp_line_limit
+ && data_left > 0 && *data_start == '.')
smtp_fputc('.', session->stream);
if (var_smtp_line_limit > 0 && data_left >= state->space_left) {
smtp_fputs(data_start, state->space_left, session->stream);
diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in
index bb8cc7189..32fbaeb2b 100644
--- a/postfix/src/smtpd/Makefile.in
+++ b/postfix/src/smtpd/Makefile.in
@@ -197,6 +197,7 @@ smtpd_check.o: ../../include/maps.h
smtpd_check.o: ../../include/mail_addr_find.h
smtpd_check.o: ../../include/match_parent_style.h
smtpd_check.o: ../../include/strip_addr.h
+smtpd_check.o: ../../include/virtual8.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
smtpd_check.o: smtpd_sasl_glue.h
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index 88308b543..0c94c4cca 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -727,7 +727,7 @@ static const char *check_maps_find(SMTPD_STATE *state, const char *reply_name,
/* checkv8_maps_find - reject with temporary failure if dict lookup fails */
static const char *checkv8_maps_find(SMTPD_STATE *state, const char *reply_name,
- MAPS *maps, const char *key)
+ MAPS *maps, const char *key)
{
const char *result;
@@ -767,12 +767,11 @@ static int resolve_final(SMTPD_STATE *state, const char *reply_name,
msg_warn("list domain %s in only one of $%s and $%s",
domain, VAR_MYDEST, VAR_VIRTUAL_MAPS);
if (*var_virt_mailbox_maps
- && checkv8_maps_find(state, reply_name, virt_mailbox_maps, domain))
+ && checkv8_maps_find(state, reply_name, virt_mailbox_maps, domain))
msg_warn("list domain %s in only one of $%s and $%s",
domain, VAR_MYDEST, VAR_VIRT_MAILBOX_MAPS);
return (1);
}
-
/* If Postfix-style virtual domain. */
if (*var_virtual_maps
&& check_maps_find(state, reply_name, virtual_maps, domain, 0))
@@ -1966,8 +1965,8 @@ static int reject_sender_login_mismatch(SMTPD_STATE *state, const char *sender)
* the sender address.
*/
reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, sender);
- owner = check_maps_find(state, sender, smtpd_sender_login_maps,
- STR(reply->recipient), 0);
+ owner = check_mail_addr_find(state, sender, smtpd_sender_login_maps,
+ STR(reply->recipient), (char **) 0);
#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable && state->sasl_username != 0)
login = state->sasl_username;
@@ -2061,8 +2060,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
cpp[1], PERMIT_ALL);
} else if (strcasecmp(name, DEFER_ALL) == 0) {
status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: %s rejected: Try again later",
- var_defer_code, reply_name, reply_class);
+ "%d <%s>: %s rejected: Try again later",
+ var_defer_code, reply_name, reply_class);
if (cpp[1] != 0 && state->warn_if_reject == 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], DEFER_ALL);
@@ -2120,7 +2119,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
}
} else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
msg_warn("restriction %s is deprecated. Use %s instead",
- PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS);
+ PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS);
if (state->helo_name) {
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
&& (status = reject_invalid_hostaddr(state, state->helo_name,
diff --git a/postfix/src/smtpstone/Makefile.in b/postfix/src/smtpstone/Makefile.in
index fb9cacbdc..186538bb6 100644
--- a/postfix/src/smtpstone/Makefile.in
+++ b/postfix/src/smtpstone/Makefile.in
@@ -118,6 +118,7 @@ smtp-sink.o: ../../include/iostuff.h
smtp-sink.o: ../../include/events.h
smtp-sink.o: ../../include/mymalloc.h
smtp-sink.o: ../../include/msg_vstream.h
+smtp-sink.o: ../../include/stringops.h
smtp-sink.o: ../../include/smtp_stream.h
smtp-source.o: smtp-source.c
smtp-source.o: ../../include/sys_defs.h
diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c
index 0b62b26df..ac3fac7f5 100644
--- a/postfix/src/smtpstone/smtp-sink.c
+++ b/postfix/src/smtpstone/smtp-sink.c
@@ -22,8 +22,13 @@
/* .IP \fB-c\fR
/* Display a running counter that is updated whenever an SMTP
/* QUIT command is executed.
+/* .IP \fB-e\fR
+/* Disable ESMTP support.
+/* .IP \fB-h\fI hostname\fR
+/* Use \fIhostname\fR in the SMTP greeting, in the HELO response,
+/* and in the EHLO response. The default hostname is "smtp-sink".
/* .IP \fB-L\fR
-/* Speak LMTP rather than SMTP.
+/* Enable LMTP rather than SMTP.
/* .IP "\fB-n \fIcount\fR"
/* Terminate after \fIcount\fR sessions. This is for testing purposes.
/* .IP \fB-p\fR
@@ -31,10 +36,18 @@
/* .IP \fB-P\fR
/* Change the server greeting so that it appears to come through
/* a CISCO PIX system.
+/* .IP "\fB-s \fIcommand,command,...\fR"
+/* Log the named commands to syslogd.
+/* Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL,
+/* RCPT, VRFY, RSET, NOOP, and QUIT. Separate command names by white
+/* space or commas, and use quotes to protect white space from the
+/* shell. Command names are case-insensitive.
/* .IP \fB-v\fR
/* Show the SMTP conversations.
/* .IP "\fB-w \fIdelay\fR"
/* Wait \fIdelay\fR seconds before responding to a DATA command.
+/* .IP \fB-8\fR
+/* Disable 8BITMIME support.
/* .IP [\fBinet:\fR][\fIhost\fR]:\fIport\fR
/* Listen on network interface \fIhost\fR (default: any interface)
/* TCP port \fIport\fR. Both \fIhost\fR and \fIport\fR may be
@@ -66,6 +79,7 @@
#include
#include
#include
+#include
#ifdef STRCASECMP_IN_STRINGS_H
#include
@@ -83,6 +97,7 @@
#include
#include
#include
+#include
/* Global library. */
@@ -115,7 +130,9 @@ static int count;
static int counter;
static int max_count;
static int disable_pipelining;
+static int disable_8bitmime;
static int fixed_delay;
+static int disable_esmtp;
static int enable_lmtp;
static int pretend_pix;
@@ -126,7 +143,16 @@ static void ehlo_response(SINK_STATE *state)
smtp_printf(state->stream, "250-%s", var_myhostname);
if (!disable_pipelining)
smtp_printf(state->stream, "250-PIPELINING");
- smtp_printf(state->stream, "250 8BITMIME");
+ if (!disable_8bitmime)
+ smtp_printf(state->stream, "250-8BITMIME");
+ smtp_printf(state->stream, "250 ");
+}
+
+/* helo_response - respond to HELO command */
+
+static void helo_response(SINK_STATE *state)
+{
+ smtp_printf(state->stream, "250 %s", var_myhostname);
}
/* ok_response - send 250 OK */
@@ -261,22 +287,54 @@ static int data_read(SINK_STATE *state)
typedef struct SINK_COMMAND {
char *name;
void (*response) (SINK_STATE *);
+ int flags;
} SINK_COMMAND;
+#define FLAG_ENABLE (1<<0) /* command is enabled */
+#define FLAG_SYSLOG (1<<1) /* log the command */
+
static SINK_COMMAND command_table[] = {
- "helo", ok_response,
- "ehlo", ehlo_response,
- "lhlo", ehlo_response,
- "mail", mail_response,
- "rcpt", rcpt_response,
- "data", data_response,
- "rset", ok_response,
- "noop", ok_response,
- "vrfy", ok_response,
- "quit", quit_response,
+ "helo", helo_response, 0,
+ "ehlo", ehlo_response, 0,
+ "lhlo", ehlo_response, 0,
+ "mail", mail_response, FLAG_ENABLE,
+ "rcpt", rcpt_response, FLAG_ENABLE,
+ "data", data_response, FLAG_ENABLE,
+ "rset", ok_response, FLAG_ENABLE,
+ "noop", ok_response, FLAG_ENABLE,
+ "vrfy", ok_response, FLAG_ENABLE,
+ "quit", quit_response, FLAG_ENABLE,
0,
};
+/* set_cmd_flags - set per-command command flags */
+
+static void set_cmd_flags(const char *cmd, int flags)
+{
+ SINK_COMMAND *cmdp;
+
+ for (cmdp = command_table; cmdp->name != 0; cmdp++)
+ if (strcasecmp(cmd, cmdp->name) == 0)
+ break;
+ if (cmdp->name == 0)
+ msg_fatal("unknown command: %s", cmd);
+ cmdp->flags |= flags;
+}
+
+/* set_cmds_flags - set per-command flags for multiple commands */
+
+static void set_cmds_flags(const char *cmds, int flags)
+{
+ char *saved_cmds;
+ char *cp;
+ char *cmd;
+
+ saved_cmds = cp = mystrdup(cmds);
+ while ((cmd = mystrtok(&cp, " \t\r\n,")) != 0)
+ set_cmd_flags(cmd, flags);
+ myfree(saved_cmds);
+}
+
/* command_read - talk the SMTP protocol, server side */
static int command_read(SINK_STATE *state)
@@ -294,6 +352,7 @@ static int command_read(SINK_STATE *state)
ST_CR, '\n', ST_CR_LF,
};
struct cmd_trans *cp;
+ char *ptr;
/*
* A read may result in EOF, but is never supposed to time out - a time
@@ -331,6 +390,12 @@ static int command_read(SINK_STATE *state)
/*
* We must avoid blocking I/O, so get out of here as soon as both the
* VSTREAM and kernel read buffers dry up.
+ *
+ * XXX Solaris non-blocking read() may fail on a socket when ioctl
+ * FIONREAD reports there is unread data. Diagnosis by Max Pashkov.
+ * As a workaround we use readable() (which uses poll or select())
+ * instead of peek_fd() (which uses ioctl FIONREAD). Workaround added
+ * 20020604.
*/
if (vstream_peek(state->stream) <= 0
&& readable(vstream_fileno(state->stream)) <= 0)
@@ -350,7 +415,8 @@ static int command_read(SINK_STATE *state)
/*
* Got a complete command line. Parse it.
*/
- if ((command = strtok(vstring_str(state->buffer), " \t")) == 0) {
+ ptr = vstring_str(state->buffer);
+ if ((command = mystrtok(&ptr, " \t")) == 0) {
smtp_printf(state->stream, "500 Error: unknown command");
return (0);
}
@@ -359,10 +425,13 @@ static int command_read(SINK_STATE *state)
for (cmdp = command_table; cmdp->name != 0; cmdp++)
if (strcasecmp(command, cmdp->name) == 0)
break;
- if (cmdp->name == 0) {
+ if (cmdp->name == 0 || (cmdp->flags & FLAG_ENABLE) == 0) {
smtp_printf(state->stream, "500 Error: unknown command");
return (0);
}
+ /* We use raw syslog. Sanitize data content and length. */
+ if (cmdp->flags & FLAG_SYSLOG)
+ syslog(LOG_INFO, "%s %.100s", command, printable(ptr, '?'));
if (cmdp->response == data_response && fixed_delay > 0) {
event_request_timer(data_event, (char *) state, fixed_delay);
} else {
@@ -413,7 +482,7 @@ static void disconnect(SINK_STATE *state)
vstream_fclose(state->stream);
vstring_free(state->buffer);
myfree((char *) state);
- if (max_count > 0 && counter >= max_count)
+ if (max_count > 0 && ++counter >= max_count)
exit(0);
}
@@ -447,10 +516,12 @@ static void connect_event(int unused_event, char *context)
state->read = command_read;
state->data_state = ST_ANY;
smtp_timeout_setup(state->stream, var_tmout);
-if (pretend_pix)
- smtp_printf(state->stream, "220 ********");
-else
- smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
+ if (pretend_pix)
+ smtp_printf(state->stream, "220 ********");
+ else if (disable_esmtp)
+ smtp_printf(state->stream, "220 %s", var_myhostname);
+ else
+ smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
event_enable_read(fd, read_event, (char *) state);
}
}
@@ -459,7 +530,7 @@ else
static void usage(char *myname)
{
- msg_fatal("usage: %s [-cLpPv] [-n count] [-w delay] [host]:port backlog", myname);
+ msg_fatal("usage: %s [-ceLpPv8] [-h hostname] [-n count] [-s commands] [-w delay] [host]:port backlog", myname);
}
int main(int argc, char **argv)
@@ -476,11 +547,17 @@ int main(int argc, char **argv)
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "cLn:pPvw:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "ceh:Ln:pPs:vw:8")) > 0) {
switch (ch) {
case 'c':
count++;
break;
+ case 'e':
+ disable_esmtp = 1;
+ break;
+ case 'h':
+ var_myhostname = optarg;
+ break;
case 'L':
enable_lmtp = 1;
break;
@@ -491,7 +568,11 @@ int main(int argc, char **argv)
disable_pipelining = 1;
break;
case 'P':
- pretend_pix=1;
+ pretend_pix = 1;
+ break;
+ case 's':
+ openlog(basename(argv[0]), LOG_PID, LOG_MAIL);
+ set_cmds_flags(optarg, FLAG_SYSLOG);
break;
case 'v':
msg_verbose++;
@@ -500,6 +581,9 @@ int main(int argc, char **argv)
if ((fixed_delay = atoi(optarg)) <= 0)
usage(argv[0]);
break;
+ case '8':
+ disable_8bitmime = 1;
+ break;
default:
usage(argv[0]);
}
@@ -512,7 +596,11 @@ int main(int argc, char **argv)
/*
* Initialize.
*/
- var_myhostname = "smtp-sink";
+ if (var_myhostname == 0)
+ var_myhostname = "smtp-sink";
+ set_cmds_flags(enable_lmtp ? "lhlo" :
+ disable_esmtp ? "helo" :
+ "helo, ehlo", FLAG_ENABLE);
if (strncmp(argv[optind], "unix:", 5) == 0) {
sock = unix_listen(argv[optind] + 5, backlog, BLOCKING);
} else {