]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5-20071221
authorWietse Venema <wietse@porcupine.org>
Fri, 21 Dec 2007 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:33:44 +0000 (06:33 +0000)
30 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/MILTER_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/MILTER_README.html
postfix/html/cleanup.8.html
postfix/html/postconf.5.html
postfix/html/smtp-sink.1.html
postfix/html/smtpd.8.html
postfix/man/man1/smtp-sink.1
postfix/man/man5/postconf.5
postfix/man/man8/cleanup.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/MILTER_README.html
postfix/proto/postconf.proto
postfix/src/cleanup/cleanup.c
postfix/src/cleanup/cleanup_init.c
postfix/src/cleanup/cleanup_milter.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/milter/Makefile.in
postfix/src/milter/milter.c
postfix/src/milter/milter.h
postfix/src/milter/milter8.c
postfix/src/milter/test-milter.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpstone/smtp-sink.c

index 2893e6b51e533a8a770ce0d0011deadadca4b634..30e4668578cdf40eaabd545bef35eb9e95be6d5f 100644 (file)
 -Tregmatch_t
 -Tsasl_conn_t
 -Tsasl_secret_t
+-Tsfsistat
 -Tsize_t
 -Tssize_t
 -Ttls_client_init_props
index 73eebcbeac62023c9cca6eb3bb5d35a57f5a5acb..98f384feef1a7c6ec813dee31f29d1fe7ad76b41 100644 (file)
@@ -14029,3 +14029,22 @@ Apologies for any names omitted.
        Cleanup: replaced documentation references to xxgdb by ddd.
        The xxgdb program hasn't been updated in more than 10 years.
        Files: proto/postconf.proto, conf/main.cf.
+
+20071219-20
+
+       Feature: support for all new Sendmail 8.14 Milter features
+       except SMFIR_SKIP (skip further events of this type),
+       SMFIP_RCPT_REJ (report rejected recipients to the mail
+       filter), SMFIR_CHGFROM (replace sender, with optional ESMTP
+       command parameters), and SMFIR_ADDRCPT_PAR (add recipient,
+       with optional ESMTP command parameters). Files: milter/milters.c,
+       milter/milter8.c, milter/test-milter.c, cleanup/cleanup_milter.c.
+
+20071221
+
+       Feature: support for Sendmail 8.14 Milter SMFIR_SKIP (skip
+       further events of this type). Files: milter/milter8.c,
+       milter/test-milter.c.
+
+       Cleanup: don't try sending HELO after a 421 EHLO reply.
+       File: smtp/smtp_proto.c.
index 39e50336f7dc4ed89016d482558dcd10f7ea1a03..cf901786c43b1cf630e254daec6ead855761600a 100644 (file)
@@ -252,6 +252,7 @@ status, so that the client will try again later. Specify "accept" if you want
 to receive mail as if the filter does not exist, and "reject" to reject mail
 with a permanent status.
 
+    /etc/postfix/main.cf:
         # What to do in case of errors? Specify accept, reject, or tempfail.
         milter_default_action = tempfail
 
@@ -259,9 +260,11 @@ M\bMi\bil\blt\bte\ber\br p\bpr\bro\bot\bto\boc\bco\bol\bl v\bve\ber\brs\bsi\bio\bon\bn
 
 As Postfix is not built with the Sendmail libmilter library, you may need to
 configure the Milter protocol version that Postfix should use. The default
-version is 2.
+version is 2. Other protocol versions are 3 and 4 (Postfix 2.3 and later), and
+6 (Postfix 2.5 an later).
 
-    milter_protocol = 2
+    /etc/postfix/main.cf:
+        milter_protocol = 2
 
 If the Postfix milter_protocol setting specifies a too low version, the
 libmilter library will log an error message like this:
@@ -308,25 +311,25 @@ with before-queue filtering.
 S\bSe\ben\bnd\bdm\bma\bai\bil\bl m\bma\bac\bcr\bro\bo e\bem\bmu\bul\bla\bat\bti\bio\bon\bn
 
 Postfix emulates a limited number of Sendmail macros, as shown in the table.
-Different macros are available at different SMTP protocol stages (EOM = end-of-
-message); their availability is not always the same as in Sendmail. See the
-workarounds section below for solutions.
+Different macros are available at different SMTP protocol stages (EOH = end-of-
+header, EOM = end-of-message); their availability is not always the same as in
+Sendmail. See the workarounds section below for solutions.
 
      _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
     |N\bNa\bam\bme\be                |A\bAv\bva\bai\bil\bla\bab\bbi\bil\bli\bit\bty\by             |D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn               |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |i                   |DATA, EOM                |Queue ID                  |
+    |i                   |DATA, EOH, EOM           |Queue ID                  |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |j                   |Always                   |value of myhostname       |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |_                   |Always                   |The validated client name |
     |                    |                         |and address               |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{auth_authen}       |MAIL, DATA, EOM          |SASL login name           |
+    |{auth_authen}       |MAIL, DATA, EOH, EOM     |SASL login name           |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{auth_author}       |MAIL, DATA, EOM          |SASL sender               |
+    |{auth_author}       |MAIL, DATA, EOH, EOM     |SASL sender               |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{auth_type}         |MAIL, DATA, EOM          |SASL login method         |
+    |{auth_type}         |MAIL, DATA, EOH, EOM     |SASL login method         |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |{client_addr}       |Always                   |Client IP address         |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
@@ -344,15 +347,17 @@ workarounds section below for solutions.
     |{client_ptr}        |CONNECT, HELO, MAIL, DATA|lookup, "unknown" when    |
     |                    |                         |lookup fails              |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{cert_issuer}       |HELO, MAIL, DATA, EO   |TLS client certificate    |
-    |                    |                         |issuer                    |
+    |{cert_issuer}       |HELO, MAIL, DATA, EOH,   |TLS client certificate    |
+    |                    |EOM                      |issuer                    |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{cert_subject}      |HELO, MAIL, DATA, EO   |TLS client certificate    |
-    |                    |                         |subject                   |
+    |{cert_subject}      |HELO, MAIL, DATA, EOH,   |TLS client certificate    |
+    |                    |EOM                      |subject                   |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{cipher_bits}       |HELO, MAIL, DATA, EOM    |TLS session key size      |
+    |{cipher_bits}       |HELO, MAIL, DATA, EOH,   |TLS session key size      |
+    |                    |EOM                      |                          |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{cipher}            |HELO, MAIL, DATA, EOM    |TLS cipher                |
+    |{cipher}            |HELO, MAIL, DATA, EOH,   |TLS cipher                |
+    |                    |EOM                      |                          |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |{daemon_name}       |Always                   |value of                  |
     |                    |                         |milter_macro_daemon_name  |
@@ -361,14 +366,15 @@ workarounds section below for solutions.
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |{rcpt_addr}         |RCPT                     |Recipient address         |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |{tls_version}       |HELO, MAIL, DATA, EOM    |TLS protocol version      |
+    |{tls_version}       |HELO, MAIL, DATA, EOH,   |TLS protocol version      |
+    |                    |EOM                      |                          |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |v                   |Always                   |value of milter_macro_v   |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 
 Postfix sends specific sets of macros at different SMTP protocol stages. The
-sets are configured with the parameters as described in the table (EOM = end of
-message).
+sets are configured with the parameters as described in the table (EOH = end of
+headers; EOM = end of message).
 
      _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
     |P\bPa\bar\bra\bam\bme\bet\bte\ber\br n\bna\bam\bme\be               |P\bPr\bro\bot\bto\boc\bco\bol\bl v\bve\ber\brs\bsi\bio\bon\bn|P\bPr\bro\bot\bto\boc\bco\bol\bl s\bst\bta\bag\bge\be |
@@ -383,6 +389,8 @@ message).
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |milter_data_macros           |4 or higher     |DATA           |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |milter_end_of_header_macros  |6 or higher     |EOH            |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |milter_end_of_data_macros    |2 or higher     |EOM            |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |milter_unknown_command_macros|3 or higher     |unknown command|
@@ -484,9 +492,10 @@ limitations will be removed as the implementation is extended over time. Of
 course the usual limitations of before-queue filtering will always apply. See
 the CONTENT_INSPECTION_README document for a discussion.
 
-  * Postfix currently supports only applications that speak the Sendmail 8
-    Milter protocol versions 2..4. Support for other protocol types or protocol
-    versions may be added later.
+  * Postfix version 2.3 introduces support for Sendmail 8 milter protocol
+    versions 2, 3 and 4; Postfix version 2.5 adds support for protocol version
+    6, which is available with Sendmail 8.14. Support for other protocol types
+    or protocol versions may be added later.
 
   * For applications that are written in C, you need to use the Sendmail
     libmilter library. A Postfix replacement may be provided in the future.
@@ -523,6 +532,11 @@ the CONTENT_INSPECTION_README document for a discussion.
 
     The solution is to use Postfix version 2.4 or later.
 
+  * Postfix version 2.5 implements the Sendmail 8.14 features except:
+    SMFIP_RCPT_REJ (report rejected recipients to the mail filter),
+    SMFIR_CHGFROM (replace sender, with optional ESMTP command parameters), and
+    SMFIR_ADDRCPT_PAR (add recipient, with optional ESMTP command parameters).
+
   * Most Milter configuration options are global. Future Postfix versions may
     support per-Milter timeouts, per-Milter error handling, etc.
 
index 0425bc5b2fc3ba94ebad5c96ee2cd54d913db83f..5047076710c844fa37951aaa3963f05c43501e0c 100644 (file)
@@ -11,6 +11,50 @@ instead, a new snapshot is released.
 The mail_release_date configuration parameter (format: yyyymmdd)
 specifies the release date of a stable release or snapshot release.
 
+Major changes with Postfix snapshot 20071221
+============================================
+
+Support for most of the Sendmail 8.14 Milter protocol features.
+
+To enable the new features specify "milter_protocol = 6" and link
+the filter application with a libmilter library from Sendmail 8.14
+or later.
+
+Sendmail 8.14 Milter features supported at this time:
+
+- NR_CONN, NR_HELO, NR_MAIL, NR_RCPT, NR_DATA, NR_UNKN, NR_HDR, 
+  NR_EOH, NR_BODY: The filter can tell Postfix that it won't reply
+  to some of the SMTP events that Postfix sends. This makes the      
+  protocol less chatty and improves performance.
+
+- SKIP: The filter can tell Postfix to skip sending the rest of    
+  the message body, which also improves performance.
+
+- HDR_LEADSPC: The filter can request that Postfix does not delete 
+  the first space character between header name and header value       
+  when sending a header to the filter, and that Postfix does not
+  insert a space character between header name and header value 
+  when receiving a header from the filter.  This fixes a limitation
+  in the old Milter protocol that can break DKIM and DK signatures.
+
+- SETSYMLIST: The filter can override one or more of the main.cf
+  milter_xxx_macros parameter settings.
+Sendmail 8.14 Milter features not supported at this time:
+
+- RCPT_REJ: report rejected recipients to the mail filter. 
+
+- CHGFROM: replace sender, with optional ESMTP command parameters.
+
+- ADDRCPT_PAR: add recipient, with optional ESMTP command parameters.
+
+It is unclear when (if ever) the missing features will be implemented.
+SMFIP_RCPT_REJ requires invasive changes in the SMTP server recipient
+processing and error handling.  SMFIR_CHGFROM and SMFIR_ADDRCPT_PAR
+require ESMTP command-line parsing in the cleanup server. Unfortunately,
+Sendmail's documentation does not specify what ESMTP options are
+supported, but only discusses examples of things that don't work.
+
 Incompatibility with Postfix 2.3 and earlier
 ============================================
 
index 30c45f92dcdce8d4901333767afe7bee57db00de..c4d15e13862b4501ea8d14458edc97eac3327028 100644 (file)
@@ -1,5 +1,15 @@
 Wish list:
 
+       In the SMTP client, handle 421 replies in smtp_loop() by
+       having the input function raise a flag after detecting 421
+       (kill connection caching and be sure to do the right thing
+       with RSET probes), leave the smtp_loop() per-command reply
+       handlers unchanged, and have the smtp_loop() reader loop
+       bail out with smtp_site_fail("server disconnected after
+       %s", where), but only in the case that it isn't already in
+       the final state. Handle 421 replies in HELO/EHLO with custom
+       code to prevent EHLO->HELO fall-back.
+
        Make event_drain() a proper event loop; update the zero mask,
        and don't ignore a non-empty timer queue.
 
index d5b6a09efa8007e8707252fdd2bef8ff7ec048d5..4c02b8d57c3ec3068ed1c831073e06ca0730807f 100644 (file)
@@ -429,6 +429,7 @@ not exist, and "reject" to reject mail with a permanent status.
 
 <blockquote>
 <pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     # What to do in case of errors? Specify accept, reject, or tempfail.
     <a href="postconf.5.html#milter_default_action">milter_default_action</a> = tempfail
 </pre>
@@ -438,11 +439,13 @@ not exist, and "reject" to reject mail with a permanent status.
 
 <p> As Postfix is not built with the Sendmail libmilter library,
 you may need to configure the Milter protocol version that Postfix
-should use.  The default version is 2. </p>
+should use.  The default version is 2. Other protocol versions are
+3 and 4 (Postfix 2.3 and later), and 6 (Postfix 2.5 an later).  </p>
 
 <blockquote>
 <pre>
-<a href="postconf.5.html#milter_protocol">milter_protocol</a> = 2
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#milter_protocol">milter_protocol</a> = 2
 </pre>
 </blockquote>
 
@@ -510,7 +513,8 @@ times. This is an inherent problem with before-queue filtering. </p>
 
 <p> Postfix emulates a limited number of Sendmail macros, as shown
 in the table. Different macros are available at different SMTP
-protocol stages (EOM = end-of-message); their availability is not
+protocol stages (EOH = end-of-header, EOM = end-of-message); their
+availability is not
 always the same as in Sendmail. See the <a
 href="#workarounds">workarounds</a> section below for solutions.
 </p>
@@ -522,7 +526,7 @@ href="#workarounds">workarounds</a> section below for solutions.
 <tr> <th> Name </th> <th> Availability </th> <th> Description </th>
 </tr>
 
-<tr> <td> i </td> <td> DATA, EOM </td> <td> Queue ID </td> </tr>
+<tr> <td> i </td> <td> DATA, EOH, EOM </td> <td> Queue ID </td> </tr>
 
 <tr> <td> j </td> <td> Always </td> <td> value of <a href="postconf.5.html#myhostname">myhostname</a> </td>
 </tr>
@@ -530,13 +534,13 @@ href="#workarounds">workarounds</a> section below for solutions.
 <tr> <td> _ </td> <td> Always </td> <td> The validated client name
 and address </td> </tr>
 
-<tr> <td> {auth_authen} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_authen} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 login name </td> </tr>
 
-<tr> <td> {auth_author} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_author} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 sender </td> </tr>
 
-<tr> <td> {auth_type} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_type} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 login method </td> </tr>
 
 <tr> <td> {client_addr} </td> <td> Always </td> <td> Client IP
@@ -555,16 +559,16 @@ Connection concurrency for this client </td> </tr>
 <td> Client name from reverse lookup, "unknown" when lookup fails
 </td> </tr>
 
-<tr> <td> {cert_issuer} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {cert_issuer} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS client certificate issuer </td> </tr>
 
-<tr> <td> {cert_subject} </td> <td> HELO, MAIL, DATA, EOM </td>
+<tr> <td> {cert_subject} </td> <td> HELO, MAIL, DATA, EOH, EOM </td>
 <td> TLS client certificate subject </td> </tr>
 
-<tr> <td> {cipher_bits} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {cipher_bits} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS session key size </td> </tr>
 
-<tr> <td> {cipher} </td> <td> HELO, MAIL, DATA, EOM </td> <td> TLS
+<tr> <td> {cipher} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td> TLS
 cipher </td> </tr>
 
 <tr> <td> {daemon_name} </td> <td> Always </td> <td> value of
@@ -576,7 +580,7 @@ cipher </td> </tr>
 <tr> <td> {rcpt_addr} </td> <td> RCPT </td> <td> Recipient address
 </td> </tr>
 
-<tr> <td> {tls_version} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {tls_version} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS protocol version </td> </tr>
 
 <tr> <td> v </td> <td> Always </td> <td> value of <a href="postconf.5.html#milter_macro_v">milter_macro_v</a>
@@ -588,7 +592,7 @@ TLS protocol version </td> </tr>
 
 <p> Postfix sends specific sets of macros at different SMTP protocol
 stages.  The sets are configured with the parameters as described
-in the table (EOM = end of message). </p>
+in the table (EOH = end of headers; EOM = end of message). </p>
 
 <blockquote>
 
@@ -612,6 +616,9 @@ TO </td> </tr>
 <tr> <td> <a href="postconf.5.html#milter_data_macros">milter_data_macros</a> </td> <td> 4 or higher </td> <td> DATA
 </td> </tr>
 
+<tr> <td> <a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> </td> <td> 6 or higher </td>
+<td> EOH </td> </tr>
+
 <tr> <td> <a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> </td> <td> 2 or higher </td>
 <td> EOM </td> </tr>
 
@@ -765,9 +772,11 @@ a discussion. </p>
 
 <ul>
 
-<li> <p> Postfix currently supports only applications that speak
-the Sendmail 8 Milter protocol versions 2..4. Support for other
-protocol types or protocol versions may be added later. </p>
+<li> <p> Postfix version 2.3 introduces support for Sendmail 8
+milter protocol versions 2, 3 and 4; Postfix version 2.5 adds support
+for protocol version 6, which is available with Sendmail 8.14.
+Support for other protocol types or protocol versions may be added
+later. </p>
 
 <li> <p> For applications that are written in C, you need to use
 the Sendmail libmilter library. A Postfix replacement may be 
@@ -812,6 +821,12 @@ operation will log a warning like this: </p>
 
 <p> The solution is to use Postfix version 2.4 or later. </p>
 
+<li> <p> Postfix version 2.5 implements the Sendmail 8.14 features
+except: SMFIP_RCPT_REJ (report rejected recipients to the mail
+filter), SMFIR_CHGFROM (replace sender, with optional ESMTP command
+parameters), and SMFIR_ADDRCPT_PAR (add recipient, with optional
+ESMTP command parameters).
+
 <li> <p> Most Milter configuration options are global. Future Postfix
 versions may support per-Milter timeouts, per-Milter error handling,
 etc. </p>
index 45325867fa497f76fa1ee97c4d4358efc99edb17..57236fc7cc31fe044acabfcf64fbe06a02990257 100644 (file)
@@ -211,6 +211,12 @@ CLEANUP(8)                                                          CLEANUP(8)
               The macros that are sent to  Milter  (mail  filter)
               applications after the message end-of-data.
 
+       Available in Postfix version 2.5 and later:
+
+       <b><a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> (see postconf -n output)</b>
+              The  macros  that  are sent to Milter (mail filter)
+              applications after the end of the message header.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
@@ -226,27 +232,27 @@ CLEANUP(8)                                                          CLEANUP(8)
               will handle.
 
        <b><a href="postconf.5.html#strict_8bitmime">strict_8bitmime</a> (no)</b>
-              Enable  both  <a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a>  and strict_8bit-
+              Enable both  <a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a>  and  strict_8bit-
               mime_body.
 
        <b><a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a> (no)</b>
               Reject mail with 8-bit text in message headers.
 
        <b><a href="postconf.5.html#strict_8bitmime_body">strict_8bitmime_body</a> (no)</b>
-              Reject 8-bit message body text without  8-bit  MIME
+              Reject  8-bit  message body text without 8-bit MIME
               content encoding information.
 
        <b><a href="postconf.5.html#strict_mime_encoding_domain">strict_mime_encoding_domain</a> (no)</b>
               Reject mail with invalid Content-Transfer-Encoding:
-              information for the message/* or  multipart/*  MIME
+              information  for  the message/* or multipart/* MIME
               content types.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#detect_8bit_encoding_header">detect_8bit_encoding_header</a> (yes)</b>
               Automatically detect 8BITMIME body content by look-
-              ing at Content-Transfer-Encoding: message  headers;
-              historically,  this  behavior  was hard-coded to be
+              ing  at Content-Transfer-Encoding: message headers;
+              historically, this behavior was  hard-coded  to  be
               "always on".
 
 <b>AUTOMATIC BCC RECIPIENT CONTROLS</b>
@@ -254,31 +260,31 @@ CLEANUP(8)                                                          CLEANUP(8)
        mail enters the mail system:
 
        <b><a href="postconf.5.html#always_bcc">always_bcc</a> (empty)</b>
-              Optional  address  that  receives  a  "blind carbon
+              Optional address  that  receives  a  "blind  carbon
               copy" of each message that is received by the Post-
               fix mail system.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#sender_bcc_maps">sender_bcc_maps</a> (empty)</b>
-              Optional  BCC  (blind  carbon-copy)  address lookup
+              Optional BCC  (blind  carbon-copy)  address  lookup
               tables, indexed by sender address.
 
        <b><a href="postconf.5.html#recipient_bcc_maps">recipient_bcc_maps</a> (empty)</b>
-              Optional BCC  (blind  carbon-copy)  address  lookup
+              Optional  BCC  (blind  carbon-copy)  address lookup
               tables, indexed by recipient address.
 
 <b>ADDRESS TRANSFORMATION CONTROLS</b>
-       Address  rewriting  is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
-       daemon.  The <a href="cleanup.8.html"><b>cleanup</b>(8)</a>  server  implements  table  driven
+       Address rewriting is delegated to  the  <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
+       daemon.   The  <a href="cleanup.8.html"><b>cleanup</b>(8)</a>  server  implements table driven
        address mapping.
 
        <b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a> (MAILER-DAEMON)</b>
-              The   recipient  of  mail  addressed  to  the  null
+              The  recipient  of  mail  addressed  to  the   null
               address.
 
        <b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
-              Optional address mapping lookup tables for  message
+              Optional  address mapping lookup tables for message
               headers and envelopes.
 
        <b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
@@ -289,49 +295,49 @@ CLEANUP(8)                                                          CLEANUP(8)
               Optional address mapping lookup tables for envelope
               and header sender addresses.
 
-       <b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a>     (envelope_sender,    header_sender,</b>
+       <b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a>    (envelope_sender,     header_sender,</b>
        <b>header_recipient)</b>
               What addresses are subject to address masquerading.
 
        <b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a> (empty)</b>
-              Optional list of domains whose subdomain  structure
+              Optional  list of domains whose subdomain structure
               will be stripped off in email addresses.
 
        <b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a> (empty)</b>
-              Optional  list of user names that are not subjected
-              to address masquerading, even  when  their  address
+              Optional list of user names that are not  subjected
+              to  address  masquerading,  even when their address
               matches $<a href="postconf.5.html#masquerade_domains">masquerade_domains</a>.
 
        <b><a href="postconf.5.html#propagate_unmatched_extensions">propagate_unmatched_extensions</a> (canonical, virtual)</b>
-              What  address  lookup tables copy an address exten-
+              What address lookup tables copy an  address  exten-
               sion from the lookup key to the lookup result.
 
        Available before Postfix version 2.0:
 
        <b><a href="postconf.5.html#virtual_maps">virtual_maps</a> (empty)</b>
               Optional lookup tables with a) names of domains for
-              which  all  addresses  are  aliased to addresses in
-              other local or remote  domains,  and  b)  addresses
-              that  are  aliased  to  addresses in other local or
+              which all addresses are  aliased  to  addresses  in
+              other  local  or  remote  domains, and b) addresses
+              that are aliased to addresses  in  other  local  or
               remote domains.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
-              Optional lookup tables  that  alias  specific  mail
-              addresses  or  domains  to  other  local  or remote
+              Optional  lookup  tables  that  alias specific mail
+              addresses or  domains  to  other  local  or  remote
               address.
 
        Available in Postfix version 2.2 and later:
 
-       <b><a href="postconf.5.html#canonical_classes">canonical_classes</a>  (envelope_sender,   envelope_recipient,</b>
+       <b><a href="postconf.5.html#canonical_classes">canonical_classes</a>   (envelope_sender,  envelope_recipient,</b>
        <b>header_sender, header_recipient)</b>
-              What  addresses  are  subject   to   <a href="postconf.5.html#canonical_maps">canonical_maps</a>
+              What   addresses   are  subject  to  <a href="postconf.5.html#canonical_maps">canonical_maps</a>
               address mapping.
 
        <b><a href="postconf.5.html#recipient_canonical_classes">recipient_canonical_classes</a>           (envelope_recipient,</b>
        <b>header_recipient)</b>
-              What  addresses  are  subject  to <a href="postconf.5.html#recipient_canonical_maps">recipient_canoni</a>-
+              What addresses  are  subject  to  <a href="postconf.5.html#recipient_canonical_maps">recipient_canoni</a>-
               <a href="postconf.5.html#recipient_canonical_maps">cal_maps</a> address mapping.
 
        <b><a href="postconf.5.html#sender_canonical_classes">sender_canonical_classes</a> (envelope_sender, header_sender)</b>
@@ -339,15 +345,15 @@ CLEANUP(8)                                                          CLEANUP(8)
               address mapping.
 
        <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
-              Don't  rewrite  message headers from remote clients
+              Don't rewrite message headers from  remote  clients
               at all when this parameter is empty; otherwise, re-
-              write  message  headers  and  append  the specified
+              write message  headers  and  append  the  specified
               domain name to incomplete addresses.
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#duplicate_filter_limit">duplicate_filter_limit</a> (1000)</b>
-              The maximal number of addresses remembered  by  the
-              address  duplicate  filter  for  <a href="aliases.5.html"><b>aliases</b>(5)</a> or <a href="virtual.5.html"><b>vir-</b></a>
+              The  maximal  number of addresses remembered by the
+              address duplicate filter  for  <a href="aliases.5.html"><b>aliases</b>(5)</a>  or  <a href="virtual.5.html"><b>vir-</b></a>
               <a href="virtual.5.html"><b>tual</b>(5)</a> alias expansion, or for <a href="showq.8.html"><b>showq</b>(8)</a> queue dis-
               plays.
 
@@ -356,16 +362,16 @@ CLEANUP(8)                                                          CLEANUP(8)
               message header.
 
        <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
-              The maximal number of  Received:   message  headers
+              The  maximal  number  of Received:  message headers
               that is allowed in the primary message headers.
 
        <b><a href="postconf.5.html#in_flow_delay">in_flow_delay</a> (1s)</b>
-              Time  to pause before accepting a new message, when
+              Time to pause before accepting a new message,  when
               the message arrival rate exceeds the message deliv-
               ery rate.
 
        <b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
-              The  maximal  size in bytes of a message, including
+              The maximal size in bytes of a  message,  including
               envelope information.
 
        Available in Postfix version 2.0 and later:
@@ -383,35 +389,35 @@ CLEANUP(8)                                                          CLEANUP(8)
               will handle.
 
        <b><a href="postconf.5.html#queue_file_attribute_count_limit">queue_file_attribute_count_limit</a> (100)</b>
-              The  maximal number of (name=value) attributes that
+              The maximal number of (name=value) attributes  that
               may be stored in a Postfix queue file.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#virtual_alias_expansion_limit">virtual_alias_expansion_limit</a> (1000)</b>
-              The maximal number of addresses that virtual  alias
+              The  maximal number of addresses that virtual alias
               expansion produces from each original recipient.
 
        <b><a href="postconf.5.html#virtual_alias_recursion_limit">virtual_alias_recursion_limit</a> (1000)</b>
-              The  maximal  nesting depth of virtual alias expan-
+              The maximal nesting depth of virtual  alias  expan-
               sion.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
+              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much time a Postfix daemon process may take to
-              handle a request  before  it  is  terminated  by  a
+              How much time a Postfix daemon process may take  to
+              handle  a  request  before  it  is  terminated by a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The  maximal  number  of  digits  after the decimal
+              The maximal number  of  digits  after  the  decimal
               point when logging sub-second delay values.
 
        <b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
-              The time after which the sender receives  the  mes-
+              The  time  after which the sender receives the mes-
               sage headers of mail that is still queued.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -419,13 +425,13 @@ CLEANUP(8)                                                          CLEANUP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits  for  an incoming connection
+              The  maximum  amount  of  time that an idle Postfix
+              daemon process waits  for  an  incoming  connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
@@ -433,19 +439,19 @@ CLEANUP(8)                                                          CLEANUP(8)
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The domain name that locally-posted mail appears to
-              come  from,  and that locally posted mail is deliv-
+              come from, and that locally posted mail  is  deliv-
               ered to.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The location of the Postfix top-level queue  direc-
+              The  location of the Postfix top-level queue direc-
               tory.
 
        <b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
@@ -456,14 +462,14 @@ CLEANUP(8)                                                          CLEANUP(8)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The mail system  name  that  is  prepended  to  the
-              process  name  in  syslog  records, so that "smtpd"
+              The  mail  system  name  that  is  prepended to the
+              process name in syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#enable_original_recipient">enable_original_recipient</a> (yes)</b>
-              Enable  support  for  the   X-Original-To   message
+              Enable   support   for  the  X-Original-To  message
               header.
 
 <b>FILES</b>
@@ -487,7 +493,7 @@ CLEANUP(8)                                                          CLEANUP(8)
        <a href="CONTENT_INSPECTION_README.html">CONTENT_INSPECTION_README</a> content inspection
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index d3d1e2b9b79ece7de991af7952582923ec4a6dfe..0ea951e41726ef2998330c5f6a708971b955c4b6 100644 (file)
@@ -5409,6 +5409,18 @@ available macro names and their meanings.  </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="milter_end_of_header_macros">milter_end_of_header_macros</a>
+(default: see postconf -n output)</b></DT><DD>
+
+<p> The macros that are sent to Milter (mail filter) applications
+after the end of the message header. See <a href="MILTER_README.html">MILTER_README</a> for a list
+of available macro names and their meanings.  </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="milter_helo_macros">milter_helo_macros</a>
@@ -5464,20 +5476,25 @@ for a list of available macro names and their meanings. </p>
 (default: 2)</b></DT><DD>
 
 <p> The mail filter protocol version and optional protocol extensions
-for communication with a Milter (mail filter) application. This
-information should match the protocol that is expected by the actual
-mail filter application.  </p>
+for communication with a Milter (mail filter) application. Postfix
+sends this version number during the initial protocol handshake.
+It should match the version number that is expected by the mail
+filter application (or by its Milter library).  </p>
 
 <p>Protocol versions: </p>
 
 <dl compact>
 
-<dt>2</dt> <dd>Use Sendmail 8 mail filter protocol version 2.</dd>
+<dt>2</dt> <dd>Use Sendmail 8 mail filter protocol version 2 (default
+as of Sendmail version 8.11).</dd>
 
 <dt>3</dt> <dd>Use Sendmail 8 mail filter protocol version 3.</dd>
 
 <dt>4</dt> <dd>Use Sendmail 8 mail filter protocol version 4.</dd>
 
+<dt>6</dt> <dd>Use Sendmail 8 mail filter protocol version 6 (default
+as of Sendmail version 8.14).</dd>
+
 </dl>
 
 <p>Protocol extensions: </p>
@@ -10252,6 +10269,17 @@ fully-qualified domain form, as required by the RFC. <br> The
 <a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> parameter specifies the response code to
 rejected requests (default: 504).</dd>
 
+<dt><b><a name="reject_rhsbl_helo">reject_rhsbl_helo <i>rbl_domain=d.d.d.d</i></a></b></dt>
+
+<dd>Reject the request when the HELO or EHLO hostname hostname is
+listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
+(Postfix version 2.1 and later only).  If no "<i>=d.d.d.d</i>" is
+specified, reject the request when the HELO or EHLO hostname is
+listed with any A record under <i>rbl_domain</i>. See the
+<a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a> description for additional RBL related configuration
+parameters.  This feature is available in Postfix 2.0 and later.
+</dd>
+
 <dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix &lt; 2.3: reject_unknown_hostname)</dt>
 
 <dd>Reject the request when the HELO or EHLO hostname has no DNS A
index c8cf0592e64a72e37b8380f4fa56e89a2fbbc3df..fe778618b8967a38b45ad97e3efedd1c8ab47dcf 100644 (file)
@@ -134,9 +134,9 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               and  use  quotes  to  protect  white space from the
               shell. Command names are case-insensitive.
 
-       <b>-r</b> <i>command,command,...</i>
-              Reject the specified commands  with  a  soft  (4xx)
-              error code.  This option implies <b>-p</b>.
+       <b>-Q</b> <i>command,command,...</i>
+              Disconnect after sending a 431 reply after  receiv-
+              ing one of the specified commands.
 
               Examples of commands are CONNECT, HELO, EHLO, LHLO,
               MAIL, RCPT, VRFY, DATA, ., RSET,  NOOP,  and  QUIT.
@@ -144,39 +144,49 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               and use quotes to  protect  white  space  from  the
               shell. Command names are case-insensitive.
 
+       <b>-r</b> <i>command,command,...</i>
+              Reject  the  specified  commands  with a soft (4xx)
+              error code.  This option implies <b>-p</b>.
+
+              Examples of commands are CONNECT, HELO, EHLO, LHLO,
+              MAIL,  RCPT,  VRFY,  DATA, ., 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.
+
        <b>-R</b> <i>root-directory</i>
-              Change  the process root directory to the specified
-              location.  This option requires  super-user  privi-
+              Change the process root directory to the  specified
+              location.   This  option requires super-user privi-
               leges. See also the <b>-u</b> option.
 
        <b>-s</b> <i>command,command,...</i>
               Log the named commands to syslogd.
 
               Examples of commands are CONNECT, HELO, EHLO, LHLO,
-              MAIL, RCPT, VRFY, DATA, ., RSET,  NOOP,  and  QUIT.
-              Separate  command  names  by white space or commas,
-              and use quotes to  protect  white  space  from  the
+              MAIL,  RCPT,  VRFY,  DATA, ., 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.
 
        <b>-S start-string</b>
-              An  optional  string that is prepended to each mes-
-              sage that is written to a dump file (see  the  dump
-              file  format  description  below).  The following C
+              An optional string that is prepended to  each  mes-
+              sage  that  is written to a dump file (see the dump
+              file format description  below).  The  following  C
               escape  sequences  are  supported:  \a  (bell),  \b
-              (backslace),  \f (formfeed), \n (newline), \r (car-
-              riage return), \t (horizontal  tab),  \v  (vertical
-              tab),  \<i>ddd</i>  (up to three octal digits) and \\ (the
+              (backslace), \f (formfeed), \n (newline), \r  (car-
+              riage  return),  \t  (horizontal tab), \v (vertical
+              tab), \<i>ddd</i> (up to three octal digits) and  \\  (the
               backslash character).
 
        <b>-t</b> <i>timeout</i> (default: 100)
               Limit the time for receiving a command or sending a
-              response.   The time limit is specified in seconds.
+              response.  The time limit is specified in  seconds.
 
        <b>-u</b> <i>username</i>
               Switch to the specified user privileges after open-
-              ing  the network socket and optionally changing the
-              process root directory.  This  option  is  required
-              when  the  process runs with super-user privileges.
+              ing the network socket and optionally changing  the
+              process  root  directory.  This  option is required
+              when the process runs with  super-user  privileges.
               See also the <b>-R</b> option.
 
        <b>-v</b>     Show the SMTP conversations.
@@ -186,16 +196,16 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               mand.
 
        <b>-W</b> <i>command:delay[:odds]</i>
-              Wait  <i>delay</i>  seconds  before responding to <i>command</i>.
-              If <i>odds</i> is also specified (a  number  between  1-99
-              inclusive),  wait  for  a random multiple of <i>delay</i>.
-              The random multiplier is equal  to  the  number  of
+              Wait <i>delay</i> seconds before  responding  to  <i>command</i>.
+              If  <i>odds</i>  is  also specified (a number between 1-99
+              inclusive), wait for a random  multiple  of  <i>delay</i>.
+              The  random  multiplier  is  equal to the number of
               times the program needs to roll a dice with a range
-              of 0..99 inclusive,  before  the  dice  produces  a
+              of  0..99  inclusive,  before  the  dice produces a
               result greater than or equal to <i>odds</i>.
 
        [<b>inet:</b>][<i>host</i>]:<i>port</i>
-              Listen  on  network  interface  <i>host</i>  (default: any
+              Listen on  network  interface  <i>host</i>  (default:  any
               interface) TCP port <i>port</i>. Both <i>host</i> and <i>port</i> may be
               specified in numeric or symbolic form.
 
@@ -203,68 +213,68 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               Listen on the UNIX-domain socket at <i>pathname</i>.
 
        <i>backlog</i>
-              The  maximum  length  the  queue of pending connec-
+              The maximum length the  queue  of  pending  connec-
               tions, as defined by the <b>listen</b>(2) system call.
 
 <b>DUMP FILE FORMAT</b>
-       Each dumped message contains a  sequence  of  text  lines,
-       terminated  with  the  newline  character. The sequence of
+       Each  dumped  message  contains  a sequence of text lines,
+       terminated with the newline  character.  The  sequence  of
        information is as follows:
 
        <b>o</b>      The optional string specified with the <b>-S</b> option.
 
-       <b>o</b>      The  <b>smtp-sink</b>  generated  headers  as   documented
+       <b>o</b>      The   <b>smtp-sink</b>  generated  headers  as  documented
               below.
 
-       <b>o</b>      The  message  header  and body as received from the
+       <b>o</b>      The message header and body as  received  from  the
               SMTP client.
 
        <b>o</b>      An empty line.
 
-       The format of the <b>smtp-sink</b> generated headers is  as  fol-
+       The  format  of the <b>smtp-sink</b> generated headers is as fol-
        lows:
 
        <b>X-Client-Addr:</b> <i>text</i>
               The client IP address without enclosing []. An IPv6
-              address is prefixed with "ipv6:".  This  record  is
+              address  is  prefixed  with "ipv6:". This record is
               always present.
 
        <b>X-Client-Proto:</b> <i>text</i>
-              The  client  protocol:  SMTP,  ESMTP  or LMTP. This
+              The client protocol:  SMTP,  ESMTP  or  LMTP.  This
               record is always present.
 
        <b>X-Helo-Args:</b> <i>text</i>
-              The arguments of the  last  HELO  or  EHLO  command
-              before  this mail delivery transaction. This record
-              is present only if the client sent  a  recognizable
+              The  arguments  of  the  last  HELO or EHLO command
+              before this mail delivery transaction. This  record
+              is  present  only if the client sent a recognizable
               HELO or EHLO command before the DATA command.
 
        <b>X-Mail-Args:</b> <i>text</i>
               The arguments of the MAIL command that started this
-              mail delivery transaction. This record  is  present
+              mail  delivery  transaction. This record is present
               exactly once.
 
        <b>X-Rcpt-Args:</b> <i>text</i>
-              The  arguments  of an RCPT command within this mail
-              delivery transaction. There is one record for  each
-              RCPT  command, and they are in the order as sent by
+              The arguments of an RCPT command within  this  mail
+              delivery  transaction. There is one record for each
+              RCPT command, and they are in the order as sent  by
               the client.
 
        <b>Received:</b> <i>text</i>
-              A message header for compatibility with  mail  pro-
-              cessing  software. This three-line header marks the
-              end of the headers provided by  <b>smtp-sink</b>,  and  is
+              A  message  header for compatibility with mail pro-
+              cessing software. This three-line header marks  the
+              end  of  the  headers provided by <b>smtp-sink</b>, and is
               formatted as follows:
 
               <b>from</b> <i>helo</i> <b>([</b><i>addr</i><b>])</b>
                      The HELO or EHLO command argument and client
                      IP address.  If the client did not send HELO
-                     or  EHLO,  the  client  IP  address  is used
+                     or EHLO,  the  client  IP  address  is  used
                      instead.
 
               <b>by</b> <i>host</i> <b>(smtp-sink) with</b> <i>proto</i> <b>id</b> <i>random</i><b>;</b>
-                     The hostname specified with the  <b>-h</b>  option,
-                     the   client  protocol  (see  <b>X-Client-Proto</b>
+                     The  hostname  specified with the <b>-h</b> option,
+                     the  client  protocol  (see   <b>X-Client-Proto</b>
                      above), and the pseudo-random portion of the
                      per-message capture file name.
 
@@ -275,7 +285,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
        <a href="smtp-source.1.html">smtp-source(1)</a>, SMTP/LMTP message generator
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index 1c80ad9547879679905d0aaaa0ad554c7beaf88b..13d051ff56b60db0956d26dff0fa730b4aa96f36 100644 (file)
@@ -262,144 +262,148 @@ SMTPD(8)                                                              SMTPD(8)
               Milter (mail filter) applications after an  unknown
               SMTP command.
 
-       <b><a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> (see postconf -n output)</b>
+       <b><a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> (see postconf -n output)</b>
               The  macros  that  are sent to Milter (mail filter)
+              applications after the message header.
+
+       <b><a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> (see postconf -n output)</b>
+              The macros that are sent to  Milter  (mail  filter)
               applications after the message end-of-data.
 
 <b>GENERAL CONTENT INSPECTION CONTROLS</b>
-       The following parameters are applicable for both  built-in
+       The  following parameters are applicable for both built-in
        and external content filters.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#receive_override_options">receive_override_options</a> (empty)</b>
-              Enable  or  disable  recipient validation, built-in
+              Enable or disable  recipient  validation,  built-in
               content filtering, or address mapping.
 
 <b>EXTERNAL CONTENT INSPECTION CONTROLS</b>
-       The following parameters are applicable for  both  before-
+       The  following  parameters are applicable for both before-
        queue and after-queue content filtering.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a> (empty)</b>
-              What  SMTP  clients are allowed to use the XFORWARD
+              What SMTP clients are allowed to use  the  XFORWARD
               feature.
 
 <b>SASL AUTHENTICATION CONTROLS</b>
-       Postfix SASL support (<a href="http://tools.ietf.org/html/rfc4954">RFC 4954</a>) can be used  to  authenti-
-       cate  remote  SMTP clients to the Postfix SMTP server, and
-       to authenticate the Postfix SMTP client to a  remote  SMTP
+       Postfix  SASL  support (<a href="http://tools.ietf.org/html/rfc4954">RFC 4954</a>) can be used to authenti-
+       cate remote SMTP clients to the Postfix SMTP  server,  and
+       to  authenticate  the Postfix SMTP client to a remote SMTP
        server.  See the <a href="SASL_README.html">SASL_README</a> document for details.
 
        <b><a href="postconf.5.html#broken_sasl_auth_clients">broken_sasl_auth_clients</a> (no)</b>
-              Enable  inter-operability  with  SMTP  clients that
-              implement an obsolete version of the  AUTH  command
+              Enable inter-operability  with  SMTP  clients  that
+              implement  an  obsolete version of the AUTH command
               (<a href="http://tools.ietf.org/html/rfc4954">RFC 4954</a>).
 
        <b><a href="postconf.5.html#smtpd_sasl_auth_enable">smtpd_sasl_auth_enable</a> (no)</b>
-              Enable  SASL  authentication  in  the  Postfix SMTP
+              Enable SASL  authentication  in  the  Postfix  SMTP
               server.
 
        <b><a href="postconf.5.html#smtpd_sasl_local_domain">smtpd_sasl_local_domain</a> (empty)</b>
-              The name of the Postfix SMTP  server's  local  SASL
+              The  name  of  the Postfix SMTP server's local SASL
               authentication realm.
 
        <b><a href="postconf.5.html#smtpd_sasl_security_options">smtpd_sasl_security_options</a> (noanonymous)</b>
-              Postfix  SMTP  server  SASL security options; as of
-              Postfix 2.3 the list of available features  depends
-              on  the SASL server implementation that is selected
+              Postfix SMTP server SASL security  options;  as  of
+              Postfix  2.3 the list of available features depends
+              on the SASL server implementation that is  selected
               with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
 
        <b><a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a> (empty)</b>
-              Optional lookup table with  the  SASL  login  names
+              Optional  lookup  table  with  the SASL login names
               that own sender (MAIL FROM) addresses.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_sasl_exceptions_networks">smtpd_sasl_exceptions_networks</a> (empty)</b>
-              What  remote  SMTP  clients the Postfix SMTP server
+              What remote SMTP clients the  Postfix  SMTP  server
               will not offer AUTH support to.
 
        Available in Postfix version 2.1 and 2.2:
 
        <b>smtpd_sasl_application_name (smtpd)</b>
-              The application name that the Postfix  SMTP  server
+              The  application  name that the Postfix SMTP server
               uses for SASL server initialization.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#smtpd_sasl_authenticated_header">smtpd_sasl_authenticated_header</a> (no)</b>
-              Report  the  SASL  authenticated  user  name in the
+              Report the SASL  authenticated  user  name  in  the
               <a href="smtpd.8.html"><b>smtpd</b>(8)</a> Received message header.
 
        <b><a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a> (smtpd)</b>
-              Implementation-specific information that the  Post-
-              fix  SMTP server passes through to the SASL plug-in
-              implementation    that     is     selected     with
+              Implementation-specific  information that the Post-
+              fix SMTP server passes through to the SASL  plug-in
+              implementation     that     is     selected    with
               <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
 
        <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a> (cyrus)</b>
-              The  SASL plug-in type that the Postfix SMTP server
+              The SASL plug-in type that the Postfix SMTP  server
               should use for authentication.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a> (empty)</b>
-              Search path for Cyrus SASL  application  configura-
-              tion  files,  currently  used  only  to  locate the
+              Search  path  for Cyrus SASL application configura-
+              tion files,  currently  used  only  to  locate  the
               $<a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a>.conf file.
 
 <b>STARTTLS SUPPORT CONTROLS</b>
-       Detailed information about STARTTLS configuration  may  be
+       Detailed  information  about STARTTLS configuration may be
        found in the <a href="TLS_README.html">TLS_README</a> document.
 
        <b><a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a> (empty)</b>
-              The  SMTP  TLS  security level for the Postfix SMTP
-              server; when a non-empty value is  specified,  this
+              The SMTP TLS security level for  the  Postfix  SMTP
+              server;  when  a non-empty value is specified, this
               overrides the obsolete parameters <a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> and
               <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>.
 
        <b><a href="postconf.5.html#smtpd_sasl_tls_security_options">smtpd_sasl_tls_security_options</a>         ($<a href="postconf.5.html#smtpd_sasl_security_options">smtpd_sasl_secu</a>-</b>
        <b><a href="postconf.5.html#smtpd_sasl_security_options">rity_options</a>)</b>
-              The SASL authentication security options  that  the
-              Postfix  SMTP  server  uses  for TLS encrypted SMTP
+              The  SASL  authentication security options that the
+              Postfix SMTP server uses  for  TLS  encrypted  SMTP
               sessions.
 
        <b><a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a> (300s)</b>
-              The time limit for Postfix SMTP  server  write  and
-              read  operations  during  TLS  startup and shutdown
+              The  time  limit  for Postfix SMTP server write and
+              read operations during  TLS  startup  and  shutdown
               handshake procedures.
 
        <b><a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> (empty)</b>
-              The file with the certificate of the  certification
-              authority  (CA) that issued the Postfix SMTP server
+              The  file with the certificate of the certification
+              authority (CA) that issued the Postfix SMTP  server
               certificate.
 
        <b><a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> (empty)</b>
-              The file with the certificate of the  certification
-              authority  (CA) that issued the Postfix SMTP server
+              The  file with the certificate of the certification
+              authority (CA) that issued the Postfix SMTP  server
               certificate.
 
        <b><a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a> (yes)</b>
-              Force the Postfix SMTP server to issue a  TLS  ses-
-              sion  id,  even  when TLS session caching is turned
+              Force  the  Postfix SMTP server to issue a TLS ses-
+              sion id, even when TLS session  caching  is  turned
               off (<a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_session_cache_database</a> is empty).
 
        <b><a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> (no)</b>
-              Ask a remote SMTP client for a client  certificate.
+              Ask  a remote SMTP client for a client certificate.
 
        <b><a href="postconf.5.html#smtpd_tls_auth_only">smtpd_tls_auth_only</a> (no)</b>
               When TLS encryption is optional in the Postfix SMTP
-              server, do not announce or accept SASL  authentica-
+              server,  do not announce or accept SASL authentica-
               tion over unencrypted connections.
 
        <b><a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> (5)</b>
-              The  verification depth for remote SMTP client cer-
+              The verification depth for remote SMTP client  cer-
               tificates.
 
        <b><a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> (empty)</b>
-              File with the Postfix SMTP server  RSA  certificate
+              File  with  the Postfix SMTP server RSA certificate
               in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> (empty)</b>
@@ -407,56 +411,56 @@ SMTPD(8)                                                              SMTPD(8)
               SMTP server cipher list at all TLS security levels.
 
        <b><a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a> (empty)</b>
-              File  with  the Postfix SMTP server DSA certificate
+              File with the Postfix SMTP server  DSA  certificate
               in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a> (empty)</b>
-              File with  DH  parameters  that  the  Postfix  SMTP
+              File  with  DH  parameters  that  the  Postfix SMTP
               server should use with EDH ciphers.
 
        <b><a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a> (empty)</b>
-              File  with  DH  parameters  that  the  Postfix SMTP
+              File with  DH  parameters  that  the  Postfix  SMTP
               server should use with EDH ciphers.
 
        <b><a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a> ($<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>)</b>
-              File with the Postfix SMTP server DSA  private  key
+              File  with  the Postfix SMTP server DSA private key
               in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a> ($<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>)</b>
-              File  with  the Postfix SMTP server RSA private key
+              File with the Postfix SMTP server RSA  private  key
               in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> (0)</b>
-              Enable additional Postfix SMTP  server  logging  of
+              Enable  additional  Postfix  SMTP server logging of
               TLS activity.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a> (medium)</b>
-              The  minimum TLS cipher grade that the Postfix SMTP
+              The minimum TLS cipher grade that the Postfix  SMTP
               server will use with mandatory TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a> (empty)</b>
-              Additional list  of  ciphers  or  cipher  types  to
-              exclude  from the SMTP server cipher list at manda-
+              Additional  list  of  ciphers  or  cipher  types to
+              exclude from the SMTP server cipher list at  manda-
               tory TLS security levels.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> (SSLv3, TLSv1)</b>
-              The TLS protocols  accepted  by  the  Postfix  SMTP
+              The  TLS  protocols  accepted  by  the Postfix SMTP
               server with mandatory TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_received_header">smtpd_tls_received_header</a> (no)</b>
               Request  that  the  Postfix  SMTP  server  produces
               Received:  message headers that include information
-              about  the protocol and cipher used, as well as the
-              client CommonName  and  client  certificate  issuer
+              about the protocol and cipher used, as well as  the
+              client  CommonName  and  client  certificate issuer
               CommonName.
 
        <b><a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a> (no)</b>
-              With  mandatory  TLS  encryption,  require a remote
-              SMTP client certificate in order to allow TLS  con-
+              With mandatory TLS  encryption,  require  a  remote
+              SMTP  client certificate in order to allow TLS con-
               nections to proceed.
 
        <b><a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_session_cache_database</a> (empty)</b>
-              Name  of  the  file containing the optional Postfix
+              Name of the file containing  the  optional  Postfix
               SMTP server TLS session cache.
 
        <b><a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> (3600s)</b>
@@ -464,14 +468,14 @@ SMTPD(8)                                                              SMTPD(8)
               sion cache information.
 
        <b><a href="postconf.5.html#smtpd_tls_wrappermode">smtpd_tls_wrappermode</a> (no)</b>
-              Run  the  Postfix  SMTP  server in the non-standard
-              "wrapper" mode, instead of using the STARTTLS  com-
+              Run the Postfix SMTP  server  in  the  non-standard
+              "wrapper"  mode, instead of using the STARTTLS com-
               mand.
 
        <b><a href="postconf.5.html#tls_daemon_random_bytes">tls_daemon_random_bytes</a> (32)</b>
-              The  number  of pseudo-random bytes that an <a href="smtp.8.html"><b>smtp</b>(8)</a>
-              or <a href="smtpd.8.html"><b>smtpd</b>(8)</a> process  requests  from  the  <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a>
-              server  in order to seed its internal pseudo random
+              The number of pseudo-random bytes that  an  <a href="smtp.8.html"><b>smtp</b>(8)</a>
+              or  <a href="smtpd.8.html"><b>smtpd</b>(8)</a>  process  requests  from the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a>
+              server in order to seed its internal pseudo  random
               number generator (PRNG).
 
        <b><a href="postconf.5.html#tls_high_cipherlist">tls_high_cipherlist</a></b>
@@ -483,7 +487,7 @@ SMTPD(8)                                                              SMTPD(8)
               ciphers.
 
        <b><a href="postconf.5.html#tls_low_cipherlist">tls_low_cipherlist</a> (ALL:!EXPORT:+RC4:@STRENGTH)</b>
-              The  OpenSSL  cipherlist  for "LOW" or higher grade
+              The OpenSSL cipherlist for "LOW"  or  higher  grade
               ciphers.
 
        <b><a href="postconf.5.html#tls_export_cipherlist">tls_export_cipherlist</a> (ALL:+RC4:@STRENGTH)</b>
@@ -491,22 +495,22 @@ SMTPD(8)                                                              SMTPD(8)
               ciphers.
 
        <b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
-              The  OpenSSL  cipherlist  for  "NULL" grade ciphers
+              The OpenSSL cipherlist  for  "NULL"  grade  ciphers
               that provide authentication without encryption.
 
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The following configuration parameters exist for  compati-
+       The  following configuration parameters exist for compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> (no)</b>
-              Opportunistic TLS:  announce  STARTTLS  support  to
-              SMTP  clients,  but do not require that clients use
+              Opportunistic  TLS:  announce  STARTTLS  support to
+              SMTP clients, but do not require that  clients  use
               TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> (no)</b>
-              Mandatory TLS: announce STARTTLS  support  to  SMTP
-              clients,  and  require that clients use TLS encryp-
+              Mandatory  TLS:  announce  STARTTLS support to SMTP
+              clients, and require that clients use  TLS  encryp-
               tion.
 
        <b><a href="postconf.5.html#smtpd_tls_cipherlist">smtpd_tls_cipherlist</a> (empty)</b>
@@ -514,64 +518,64 @@ SMTPD(8)                                                              SMTPD(8)
               server TLS cipher list.
 
 <b>VERP SUPPORT CONTROLS</b>
-       With  VERP  style  delivery,  each  recipient of a message
+       With VERP style delivery,  each  recipient  of  a  message
        receives a customized copy of the message with his/her own
-       recipient  address encoded in the envelope sender address.
+       recipient address encoded in the envelope sender  address.
        The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation
-       details  of  Postfix  support for variable envelope return
+       details of Postfix support for  variable  envelope  return
        path addresses.  VERP style delivery is requested with the
-       SMTP  XVERP command or with the "sendmail -V" command-line
-       option and is available in Postfix version 1.1 and  later.
+       SMTP XVERP command or with the "sendmail -V"  command-line
+       option  and is available in Postfix version 1.1 and later.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The  characters  Postfix  accepts as VERP delimiter
-              characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command  line
+              The characters Postfix accepts  as  VERP  delimiter
+              characters  on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
               and in SMTP commands.
 
        Available in Postfix version 1.1 and 2.0:
 
        <b><a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              What  SMTP clients are allowed to specify the XVERP
+              What SMTP clients are allowed to specify the  XVERP
               command.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_verp_clients">smtpd_authorized_verp_clients</a> ($<a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a>)</b>
-              What SMTP clients are allowed to specify the  XVERP
+              What  SMTP clients are allowed to specify the XVERP
               command.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
-       The  <a href="DEBUG_README.html">DEBUG_README</a> document describes how to debug parts of
-       the Postfix mail system. The methods vary from making  the
-       software  log a lot of detail, to running some daemon pro-
+       The <a href="DEBUG_README.html">DEBUG_README</a> document describes how to debug parts  of
+       the  Postfix mail system. The methods vary from making the
+       software log a lot of detail, to running some daemon  pro-
        cesses under control of a call tracer or debugger.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment  in  verbose  logging  level  when  a
-              remote  client  or  server matches a pattern in the
+              The  increment  in  verbose  logging  level  when a
+              remote client or server matches a  pattern  in  the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname
-              or  network address patterns that cause the verbose
-              logging level to increase by the  amount  specified
+              Optional  list  of remote client or server hostname
+              or network address patterns that cause the  verbose
+              logging  level  to increase by the amount specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The  recipient  of  postmaster  notifications about
-              mail delivery problems that are caused  by  policy,
+              The recipient  of  postmaster  notifications  about
+              mail  delivery  problems that are caused by policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What  categories of Postfix-generated mail are sub-
-              ject  to   before-queue   content   inspection   by
+              What categories of Postfix-generated mail are  sub-
+              ject   to   before-queue   content   inspection  by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The  list of error classes that are reported to the
+              The list of error classes that are reported to  the
               postmaster.
 
        <b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
@@ -581,22 +585,22 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a> (empty)</b>
-              What  SMTP  clients  are allowed to use the XCLIENT
+              What SMTP clients are allowed to  use  the  XCLIENT
               feature.
 
 <b>KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS</b>
-       As of Postfix version 2.0, the SMTP  server  rejects  mail
-       for  unknown recipients. This prevents the mail queue from
-       clogging up  with  undeliverable  MAILER-DAEMON  messages.
-       Additional   information   on   this   topic   is  in  the
+       As  of  Postfix  version 2.0, the SMTP server rejects mail
+       for unknown recipients. This prevents the mail queue  from
+       clogging  up  with  undeliverable  MAILER-DAEMON messages.
+       Additional  information  on   this   topic   is   in   the
        <a href="LOCAL_RECIPIENT_README.html">LOCAL_RECIPIENT_README</a> and <a href="ADDRESS_CLASS_README.html">ADDRESS_CLASS_README</a> documents.
 
        <b><a href="postconf.5.html#show_user_unknown_table_name">show_user_unknown_table_name</a> (yes)</b>
-              Display  the  name  of  the  recipient table in the
+              Display the name of  the  recipient  table  in  the
               "User unknown" responses.
 
        <b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
-              Optional address mapping lookup tables for  message
+              Optional  address mapping lookup tables for message
               headers and envelopes.
 
        <b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
@@ -607,7 +611,7 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#mydestination">mydestination</a>  ($<a href="postconf.5.html#myhostname">myhostname</a>,  localhost.$<a href="postconf.5.html#mydomain">mydomain</a>,  local-</b>
        <b>host)</b>
-              The list of domains  that  are  delivered  via  the
+              The  list  of  domains  that  are delivered via the
               $<a href="postconf.5.html#local_transport">local_transport</a> mail delivery transport.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -616,146 +620,146 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The Internet protocols Postfix will attempt to  use
+              The  Internet protocols Postfix will attempt to use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>             (<a href="proxymap.8.html">proxy</a>:unix:passwd.byname</b>
        <b>$<a href="postconf.5.html#alias_maps">alias_maps</a>)</b>
-              Lookup  tables with all names or addresses of local
-              recipients: a recipient address is local  when  its
-              domain  matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> or
+              Lookup tables with all names or addresses of  local
+              recipients:  a  recipient address is local when its
+              domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a>  or
               $<a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a>.
 
        <b><a href="postconf.5.html#unknown_local_recipient_reject_code">unknown_local_recipient_reject_code</a> (550)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when    a   recipient   address   is   local,   and
-              $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a  list  of  lookup
+              The  numerical  Postfix  SMTP  server response code
+              when   a   recipient   address   is   local,    and
+              $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>  specifies  a  list of lookup
               tables that does not match the recipient.
 
-       Parameters  concerning  known/unknown  recipients of relay
+       Parameters concerning known/unknown  recipients  of  relay
        destinations:
 
        <b><a href="postconf.5.html#relay_domains">relay_domains</a> ($<a href="postconf.5.html#mydestination">mydestination</a>)</b>
-              What destination domains (and  subdomains  thereof)
+              What  destination  domains (and subdomains thereof)
               this system will relay mail to.
 
        <b><a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> (empty)</b>
-              Optional  lookup tables with all valid addresses in
+              Optional lookup tables with all valid addresses  in
               the domains that match $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#unknown_relay_recipient_reject_code">unknown_relay_recipient_reject_code</a> (550)</b>
               The numerical Postfix SMTP server reply code when a
-              recipient   address   matches  $<a href="postconf.5.html#relay_domains">relay_domains</a>,  and
-              <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> specifies  a  list  of  lookup
+              recipient  address  matches   $<a href="postconf.5.html#relay_domains">relay_domains</a>,   and
+              <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a>  specifies  a  list  of lookup
               tables that does not match the recipient address.
 
-       Parameters  concerning known/unknown recipients in virtual
+       Parameters concerning known/unknown recipients in  virtual
        alias domains:
 
        <b><a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> ($<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>)</b>
               Postfix is final destination for the specified list
-              of  virtual  alias  domains,  that  is, domains for
-              which all addresses are  aliased  to  addresses  in
+              of virtual alias  domains,  that  is,  domains  for
+              which  all  addresses  are  aliased to addresses in
               other local or remote domains.
 
        <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
-              Optional  lookup  tables  that  alias specific mail
-              addresses or  domains  to  other  local  or  remote
+              Optional lookup tables  that  alias  specific  mail
+              addresses  or  domains  to  other  local  or remote
               address.
 
        <b><a href="postconf.5.html#unknown_virtual_alias_reject_code">unknown_virtual_alias_reject_code</a> (550)</b>
               The SMTP server reply code when a recipient address
-              matches    $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>,    and     $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
-              <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a>  specifies  a list of lookup tables
+              matches     $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>,    and    $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
+              <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a> specifies a list of  lookup  tables
               that does not match the recipient address.
 
-       Parameters concerning known/unknown recipients in  virtual
+       Parameters  concerning known/unknown recipients in virtual
        mailbox domains:
 
        <b><a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a> ($<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>)</b>
               Postfix is final destination for the specified list
-              of  domains;  mail  is  delivered  via  the   $<a href="postconf.5.html#virtual_transport">vir</a>-
+              of   domains;  mail  is  delivered  via  the  $<a href="postconf.5.html#virtual_transport">vir</a>-
               <a href="postconf.5.html#virtual_transport">tual_transport</a> mail delivery transport.
 
        <b><a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a> (empty)</b>
-              Optional  lookup tables with all valid addresses in
+              Optional lookup tables with all valid addresses  in
               the domains that match $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>.
 
        <b><a href="postconf.5.html#unknown_virtual_mailbox_reject_code">unknown_virtual_mailbox_reject_code</a> (550)</b>
               The SMTP server reply code when a recipient address
-              matches    $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,    and   $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
+              matches   $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,    and    $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
               <a href="postconf.5.html#virtual_mailbox_maps">tual_mailbox_maps</a> specifies a list of lookup tables
               that does not match the recipient address.
 
 <b>RESOURCE AND RATE CONTROLS</b>
-       The  following parameters limit resource usage by the SMTP
+       The following parameters limit resource usage by the  SMTP
        server and/or control client request rates.
 
        <b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
-              Upon input, long lines are chopped up  into  pieces
-              of  at  most this length; upon delivery, long lines
+              Upon  input,  long lines are chopped up into pieces
+              of at most this length; upon delivery,  long  lines
               are reconstructed.
 
        <b><a href="postconf.5.html#queue_minfree">queue_minfree</a> (0)</b>
-              The minimal amount of free space in  bytes  in  the
+              The  minimal  amount  of free space in bytes in the
               queue file system that is needed to receive mail.
 
        <b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
-              The  maximal  size in bytes of a message, including
+              The maximal size in bytes of a  message,  including
               envelope information.
 
        <b><a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a> (1000)</b>
-              The maximal number of recipients that  the  Postfix
+              The  maximal  number of recipients that the Postfix
               SMTP server accepts per message delivery request.
 
        <b><a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> (300s)</b>
-              The  time  limit  for sending a Postfix SMTP server
-              response and for receiving  a  remote  SMTP  client
+              The time limit for sending a  Postfix  SMTP  server
+              response  and  for  receiving  a remote SMTP client
               request.
 
        <b><a href="postconf.5.html#smtpd_history_flush_threshold">smtpd_history_flush_threshold</a> (100)</b>
-              The  maximal  number  of  lines in the Postfix SMTP
-              server command history before it  is  flushed  upon
+              The maximal number of lines  in  the  Postfix  SMTP
+              server  command  history  before it is flushed upon
               receipt of EHLO, RSET, or end of DATA.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#smtpd_peername_lookup">smtpd_peername_lookup</a> (yes)</b>
               Attempt to look up the remote SMTP client hostname,
-              and verify that the  name  matches  the  client  IP
+              and  verify  that  the  name  matches the client IP
               address.
 
        The per SMTP client connection count and request rate lim-
        its are implemented in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> ser-
-       vice,  and are available in Postfix version 2.2 and later.
+       vice, and are available in Postfix version 2.2 and  later.
 
        <b><a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a> (50)</b>
-              How many simultaneous  connections  any  client  is
+              How  many  simultaneous  connections  any client is
               allowed to make to this service.
 
        <b><a href="postconf.5.html#smtpd_client_connection_rate_limit">smtpd_client_connection_rate_limit</a> (0)</b>
               The  maximal  number  of  connection  attempts  any
-              client is allowed to make to this service per  time
+              client  is allowed to make to this service per time
               unit.
 
        <b><a href="postconf.5.html#smtpd_client_message_rate_limit">smtpd_client_message_rate_limit</a> (0)</b>
-              The  maximal  number  of  message delivery requests
-              that any client is allowed to make to this  service
+              The maximal number  of  message  delivery  requests
+              that  any client is allowed to make to this service
               per time unit, regardless of whether or not Postfix
               actually accepts those messages.
 
        <b><a href="postconf.5.html#smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a> (0)</b>
-              The maximal number of recipient addresses that  any
-              client  is allowed to send to this service per time
+              The  maximal number of recipient addresses that any
+              client is allowed to send to this service per  time
               unit, regardless of whether or not Postfix actually
               accepts those recipients.
 
        <b><a href="postconf.5.html#smtpd_client_event_limit_exceptions">smtpd_client_event_limit_exceptions</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              Clients  that  are  excluded from connection count,
+              Clients that are excluded  from  connection  count,
               connection rate, or SMTP request rate restrictions.
 
        Available in Postfix version 2.3 and later:
@@ -766,52 +770,52 @@ SMTPD(8)                                                              SMTPD(8)
               tiate with this service per time unit.
 
 <b>TARPIT CONTROLS</b>
-       When  a  remote SMTP client makes errors, the Postfix SMTP
-       server can insert delays before responding. This can  help
-       to  slow  down  run-away  software.   The behavior is con-
-       trolled by an error counter  that  counts  the  number  of
-       errors  within an SMTP session that a client makes without
+       When a remote SMTP client makes errors, the  Postfix  SMTP
+       server  can insert delays before responding. This can help
+       to slow down run-away  software.   The  behavior  is  con-
+       trolled  by  an  error  counter  that counts the number of
+       errors within an SMTP session that a client makes  without
        delivering mail.
 
        <b><a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> (1s)</b>
               With Postfix version 2.1 and later: the SMTP server
-              response  delay  after  a client has made more than
-              $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>  errors,  and  fewer   than
-              $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a>  errors, without delivering
+              response delay after a client has  made  more  than
+              $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>   errors,  and  fewer  than
+              $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> errors, without  delivering
               mail.
 
        <b><a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> (10)</b>
-              The number  of  errors  a  remote  SMTP  client  is
-              allowed  to make without delivering mail before the
+              The  number  of  errors  a  remote  SMTP  client is
+              allowed to make without delivering mail before  the
               Postfix SMTP server slows down all its responses.
 
        <b><a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> (20)</b>
-              The maximal number of errors a remote  SMTP  client
+              The  maximal  number of errors a remote SMTP client
               is allowed to make without delivering mail.
 
        <b><a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> (100)</b>
-              The  number  of  junk commands (NOOP, VRFY, ETRN or
+              The number of junk commands (NOOP,  VRFY,  ETRN  or
               RSET) that a remote SMTP client can send before the
-              Postfix  SMTP  server starts to increment the error
+              Postfix SMTP server starts to increment  the  error
               counter with each junk command.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_recipient_overshoot_limit">smtpd_recipient_overshoot_limit</a> (1000)</b>
-              The number of recipients that a remote SMTP  client
-              can  send  in  excess  of  the limit specified with
+              The  number of recipients that a remote SMTP client
+              can send in excess  of  the  limit  specified  with
               $<a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a>,  before  the  Postfix  SMTP
-              server  increments  the per-session error count for
+              server increments the per-session error  count  for
               each excess recipient.
 
 <b>ACCESS POLICY DELEGATION CONTROLS</b>
-       As of version 2.1, Postfix can be configured  to  delegate
-       access  policy  decisions  to an external server that runs
-       outside Postfix.  See  the  file  <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a>  for
+       As  of  version 2.1, Postfix can be configured to delegate
+       access policy decisions to an external  server  that  runs
+       outside  Postfix.   See  the  file <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a> for
        more information.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a> (300s)</b>
-              The  time  after which an idle SMTPD policy service
+              The time after which an idle SMTPD  policy  service
               connection is closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_ttl">smtpd_policy_service_max_ttl</a> (1000s)</b>
@@ -819,162 +823,162 @@ SMTPD(8)                                                              SMTPD(8)
               connection is closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_timeout">smtpd_policy_service_timeout</a> (100s)</b>
-              The  time  limit  for  connecting to, writing to or
+              The time limit for connecting  to,  writing  to  or
               receiving from a delegated SMTPD policy server.
 
 <b>ACCESS CONTROLS</b>
-       The <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction  to
+       The  <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to
        all the SMTP server access control features.
 
        <b><a href="postconf.5.html#smtpd_delay_reject">smtpd_delay_reject</a> (yes)</b>
-              Wait  until  the  RCPT TO command before evaluating
+              Wait until the RCPT TO  command  before  evaluating
               $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>,    $smtpd_helo_restric-
               tions and $<a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a>, or wait until
-              the     ETRN     command     before      evaluating
+              the      ETRN     command     before     evaluating
               $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> and $smtpd_helo_restric-
               tions.
 
-       <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf  -d'  out-</b>
+       <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a>  (see  'postconf -d' out-</b>
        <b>put)</b>
               What   Postfix   features   match   subdomains   of
               "domain.tld" automatically, instead of requiring an
               explicit ".domain.tld" pattern.
 
        <b><a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> (empty)</b>
-              Optional SMTP server  access  restrictions  in  the
+              Optional  SMTP  server  access  restrictions in the
               context of a client SMTP connection request.
 
        <b><a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> (no)</b>
               Require that a remote SMTP client introduces itself
-              at the beginning of an SMTP session with  the  HELO
+              at  the  beginning of an SMTP session with the HELO
               or EHLO command.
 
        <b><a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a> (empty)</b>
-              Optional  restrictions that the Postfix SMTP server
+              Optional restrictions that the Postfix SMTP  server
               applies in the context of the SMTP HELO command.
 
        <b><a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a> (empty)</b>
-              Optional restrictions that the Postfix SMTP  server
+              Optional  restrictions that the Postfix SMTP server
               applies in the context of the MAIL FROM command.
 
        <b><a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a>           (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,</b>
        <b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>)</b>
               The  access  restrictions  that  the  Postfix  SMTP
-              server applies in the context of the RCPT  TO  com-
+              server  applies  in the context of the RCPT TO com-
               mand.
 
        <b><a href="postconf.5.html#smtpd_etrn_restrictions">smtpd_etrn_restrictions</a> (empty)</b>
-              Optional  SMTP  server  access  restrictions in the
+              Optional SMTP server  access  restrictions  in  the
               context of a client ETRN request.
 
        <b><a href="postconf.5.html#allow_untrusted_routing">allow_untrusted_routing</a> (no)</b>
-              Forward   mail   with   sender-specified    routing
-              (user[@%!]remote[@%!]site)  from  untrusted clients
+              Forward    mail   with   sender-specified   routing
+              (user[@%!]remote[@%!]site) from  untrusted  clients
               to destinations matching $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> (empty)</b>
-              User-defined aliases for groups of access  restric-
+              User-defined  aliases for groups of access restric-
               tions.
 
        <b><a href="postconf.5.html#smtpd_null_access_lookup_key">smtpd_null_access_lookup_key</a> (</b>&lt;&gt;<b>)</b>
-              The  lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a> tables
+              The lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a>  tables
               instead of the null sender address.
 
        <b><a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> (empty)</b>
               Restrict  the  use  of  the  <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a>  SMTP
-              access  feature  to  only  domains whose primary MX
+              access feature to only  domains  whose  primary  MX
               hosts match the listed networks.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#smtpd_data_restrictions">smtpd_data_restrictions</a> (empty)</b>
-              Optional access restrictions that the Postfix  SMTP
+              Optional  access restrictions that the Postfix SMTP
               server applies in the context of the SMTP DATA com-
               mand.
 
        <b><a href="postconf.5.html#smtpd_expansion_filter">smtpd_expansion_filter</a> (see 'postconf -d' output)</b>
-              What characters are allowed in $name expansions  of
+              What  characters are allowed in $name expansions of
               RBL reply templates.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> (no)</b>
-              Request  that  the Postfix SMTP server rejects mail
-              from  unknown  sender  addresses,  even   when   no
-              explicit  <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
+              Request that the Postfix SMTP server  rejects  mail
+              from   unknown   sender  addresses,  even  when  no
+              explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access  restriction
               is specified.
 
        <b><a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> (yes)</b>
-              Request that the Postfix SMTP server  rejects  mail
+              Request  that  the Postfix SMTP server rejects mail
               for  unknown  recipient  addresses,  even  when  no
-              explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access  restric-
+              explicit  <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
               tion is specified.
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a> (empty)</b>
-              Optional  access restrictions that the Postfix SMTP
-              server applies in the context of the  SMTP  END-OF-
+              Optional access restrictions that the Postfix  SMTP
+              server  applies  in the context of the SMTP END-OF-
               DATA command.
 
 <b>SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS</b>
-       Postfix   version  2.1  introduces  sender  and  recipient
-       address verification.   This  feature  is  implemented  by
-       sending  probe email messages that are not actually deliv-
-       ered.  This feature is requested  via  the  <a href="postconf.5.html#reject_unverified_sender">reject_unveri</a>-
-       <a href="postconf.5.html#reject_unverified_sender">fied_sender</a>    and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>   access
-       restrictions.  The status of verification probes is  main-
+       Postfix  version  2.1  introduces  sender  and   recipient
+       address  verification.   This  feature  is  implemented by
+       sending probe email messages that are not actually  deliv-
+       ered.   This  feature  is requested via the <a href="postconf.5.html#reject_unverified_sender">reject_unveri</a>-
+       <a href="postconf.5.html#reject_unverified_sender">fied_sender</a>   and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>    access
+       restrictions.   The status of verification probes is main-
        tained by the <a href="verify.8.html"><b>verify</b>(8)</a> server.  See the file <a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VER</a>-
-       <a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a> for information about  how  to  configure
+       <a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a>  for  information  about how to configure
        and operate the Postfix sender/recipient address verifica-
        tion service.
 
        <b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (3)</b>
-              How many times to query the <a href="verify.8.html"><b>verify</b>(8)</a>  service  for
-              the  completion  of an address verification request
+              How  many  times to query the <a href="verify.8.html"><b>verify</b>(8)</a> service for
+              the completion of an address  verification  request
               in progress.
 
        <b><a href="postconf.5.html#address_verify_poll_delay">address_verify_poll_delay</a> (3s)</b>
-              The delay between queries for the completion of  an
+              The  delay between queries for the completion of an
               address verification request in progress.
 
        <b><a href="postconf.5.html#address_verify_sender">address_verify_sender</a> ($<a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a>)</b>
-              The  sender  address to use in address verification
+              The sender address to use in  address  verification
               probes; prior to Postfix 2.5 the default was "post-
               master".
 
        <b><a href="postconf.5.html#unverified_sender_reject_code">unverified_sender_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when  a  recipient  address  is  rejected  by   the
+              The numerical Postfix  SMTP  server  response  code
+              when   a  recipient  address  is  rejected  by  the
               <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a> restriction.
 
        <b><a href="postconf.5.html#unverified_recipient_reject_code">unverified_recipient_reject_code</a> (450)</b>
-              The  numerical  Postfix SMTP server response when a
+              The numerical Postfix SMTP server response  when  a
               recipient address is rejected by the <a href="postconf.5.html#reject_unverified_recipient">reject_unveri</a>-
               <a href="postconf.5.html#reject_unverified_recipient">fied_recipient</a> restriction.
 
 <b>ACCESS CONTROL RESPONSES</b>
-       The  following  parameters  control  numerical  SMTP reply
+       The following  parameters  control  numerical  SMTP  reply
        codes and/or text responses.
 
        <b><a href="postconf.5.html#access_map_reject_code">access_map_reject_code</a> (554)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  client  is  rejected  by  an <a href="access.5.html"><b>access</b>(5)</a> map
+              The  numerical  Postfix  SMTP  server response code
+              when a client  is  rejected  by  an  <a href="access.5.html"><b>access</b>(5)</a>  map
               restriction.
 
        <b><a href="postconf.5.html#defer_code">defer_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  remote  SMTP client request is rejected by
+              The  numerical  Postfix  SMTP  server response code
+              when a remote SMTP client request  is  rejected  by
               the "defer" restriction.
 
        <b><a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> (501)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  the  client HELO or EHLO command parameter is
-              rejected   by   the    <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
+              The  numerical  Postfix  SMTP  server response code
+              when the client HELO or EHLO command  parameter  is
+              rejected    by   the   <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
               restriction.
 
        <b><a href="postconf.5.html#maps_rbl_reject_code">maps_rbl_reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
+              The numerical Postfix  SMTP  server  response  code
               when a remote SMTP client request is blocked by the
               <a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>,             <a href="postconf.5.html#reject_rhsbl_client">reject_rhsbl_client</a>,
               <a href="postconf.5.html#reject_rhsbl_sender">reject_rhsbl_sender</a>    or    <a href="postconf.5.html#reject_rhsbl_recipient">reject_rhsbl_recipient</a>
@@ -982,53 +986,53 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> (504)</b>
               The numerical Postfix SMTP server reply code when a
-              client    request    is     rejected     by     the
+              client     request     is     rejected    by    the
               <a href="postconf.5.html#reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a>,
               <a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a>
               restriction.
 
        <b><a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a request is  rejected  by  the  <b>reject_plain-</b>
+              The numerical Postfix  SMTP  server  response  code
+              when  a  request  is  rejected by the <b>reject_plain-</b>
               <b>text_session</b> restriction.
 
        <b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a remote SMTP client request  is  rejected  by
+              The numerical Postfix  SMTP  server  response  code
+              when  a  remote  SMTP client request is rejected by
               the "reject" restriction.
 
        <b><a href="postconf.5.html#relay_domains_reject_code">relay_domains_reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when  a  client  request   is   rejected   by   the
+              The numerical Postfix  SMTP  server  response  code
+              when   a   client   request   is  rejected  by  the
               <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> recipient restriction.
 
        <b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when a sender or recipient address is  rejected  by
+              The numerical Postfix  SMTP  server  response  code
+              when  a  sender or recipient address is rejected by
               the         <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>         or
               <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction.
 
        <b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
-              The numerical Postfix  SMTP  server  response  code
-              when  a  client without valid address &lt;=&gt; name map-
+              The  numerical  Postfix  SMTP  server response code
+              when a client without valid address &lt;=&gt;  name  map-
               ping is rejected by the reject_unknown_client_host-
               name restriction.
 
        <b><a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server response code
-              when the hostname specified with the HELO  or  EHLO
-              command        is       rejected       by       the
+              The numerical Postfix  SMTP  server  response  code
+              when  the  hostname specified with the HELO or EHLO
+              command       is       rejected       by        the
               <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> restriction.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#default_rbl_reply">default_rbl_reply</a> (see 'postconf -d' output)</b>
-              The default SMTP server  response  template  for  a
-              request  that  is rejected by an RBL-based restric-
+              The  default  SMTP  server  response template for a
+              request that is rejected by an  RBL-based  restric-
               tion.
 
        <b><a href="postconf.5.html#multi_recipient_bounce_reject_code">multi_recipient_bounce_reject_code</a> (550)</b>
-              The numerical Postfix  SMTP  server  response  code
+              The  numerical  Postfix  SMTP  server response code
               when a remote SMTP client request is blocked by the
               <a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipient_bounce</a> restriction.
 
@@ -1037,16 +1041,16 @@ SMTPD(8)                                                              SMTPD(8)
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
-              The location of  all  postfix  administrative  com-
+              The  location  of  all  postfix administrative com-
               mands.
 
        <b><a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a> (double-bounce)</b>
@@ -1067,37 +1071,37 @@ SMTPD(8)                                                              SMTPD(8)
               and most Postfix daemon processes.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits  for  an incoming connection
+              The  maximum  amount  of  time that an idle Postfix
+              daemon process waits  for  an  incoming  connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
               The internet hostname of this mail system.
 
        <b><a href="postconf.5.html#mynetworks">mynetworks</a> (see 'postconf -d' output)</b>
-              The list of "trusted" SMTP clients that  have  more
+              The  list  of "trusted" SMTP clients that have more
               privileges than "strangers".
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The domain name that locally-posted mail appears to
-              come from, and that locally posted mail  is  deliv-
+              come  from,  and that locally posted mail is deliv-
               ered to.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The  process  ID  of  a  Postfix  command or daemon
+              The process ID  of  a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The process name of a  Postfix  command  or  daemon
+              The  process  name  of  a Postfix command or daemon
               process.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The  location of the Postfix top-level queue direc-
+              The location of the Postfix top-level queue  direc-
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
@@ -1105,28 +1109,28 @@ SMTPD(8)                                                              SMTPD(8)
               sions (user+foo).
 
        <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
-              The  text  that  follows the 220 status code in the
+              The text that follows the 220 status  code  in  the
               SMTP greeting banner.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The mail system  name  that  is  prepended  to  the
-              process  name  in  syslog  records, so that "smtpd"
+              The  mail  system  name  that  is  prepended to the
+              process name in syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT, GET, POST)</b>
-              List of  commands  that  causes  the  Postfix  SMTP
-              server  to immediately terminate the session with a
+              List  of  commands  that  causes  the  Postfix SMTP
+              server to immediately terminate the session with  a
               221 code.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#smtpd_client_port_logging">smtpd_client_port_logging</a> (no)</b>
-              Enable logging of the remote SMTP  client  port  in
+              Enable  logging  of  the remote SMTP client port in
               addition to the hostname and IP address.
 
 <b>SEE ALSO</b>
@@ -1156,7 +1160,7 @@ SMTPD(8)                                                              SMTPD(8)
        <a href="XFORWARD_README.html">XFORWARD_README</a>, Postfix XFORWARD extension
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 11cc709689e16d54043cce6d8759698ef4f38518..07818735bd89bc54df1da052d74adda209f03614 100644 (file)
@@ -117,6 +117,14 @@ Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 DATA, ., 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-Q \fIcommand,command,...\fR"
+Disconnect after sending a 431 reply after receiving one
+of the specified commands.
+.sp
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+DATA, ., 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-r \fIcommand,command,...\fR"
 Reject the specified commands with a soft (4xx) error code.
 This option implies \fB-p\fR.
index d885c6f50ea0cf61eed84b4c552f749f19457494..43469a2afe6f79e98739daa01e988a9c25a4bec9 100644 (file)
@@ -2998,6 +2998,12 @@ after the message end-of-data. See MILTER_README for a list of
 available macro names and their meanings.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH milter_end_of_header_macros (default: see postconf -n output)
+The macros that are sent to Milter (mail filter) applications
+after the end of the message header. See MILTER_README for a list
+of available macro names and their meanings.
+.PP
+This feature is available in Postfix 2.5 and later.
 .SH milter_helo_macros (default: see postconf -n output)
 The macros that are sent to Milter (mail filter) applications
 after the SMTP HELO or EHLO command. See
@@ -3024,17 +3030,22 @@ for a list of available macro names and their meanings.
 This feature is available in Postfix 2.3 and later.
 .SH milter_protocol (default: 2)
 The mail filter protocol version and optional protocol extensions
-for communication with a Milter (mail filter) application. This
-information should match the protocol that is expected by the actual
-mail filter application.
+for communication with a Milter (mail filter) application. Postfix
+sends this version number during the initial protocol handshake.
+It should match the version number that is expected by the mail
+filter application (or by its Milter library).
 .PP
 Protocol versions:
 .IP "2"
-Use Sendmail 8 mail filter protocol version 2.
+Use Sendmail 8 mail filter protocol version 2 (default
+as of Sendmail version 8.11).
 .IP "3"
 Use Sendmail 8 mail filter protocol version 3.
 .IP "4"
 Use Sendmail 8 mail filter protocol version 4.
+.IP "6"
+Use Sendmail 8 mail filter protocol version 6 (default
+as of Sendmail version 8.14).
 .PP
 Protocol extensions:
 .IP "no_header_reply"
@@ -6132,6 +6143,14 @@ fully-qualified domain form, as required by the RFC.
 The
 non_fqdn_reject_code parameter specifies the response code to
 rejected requests (default: 504).
+.IP "\fBreject_rhsbl_helo \fIrbl_domain=d.d.d.d\fR\fR"
+Reject the request when the HELO or EHLO hostname hostname is
+listed with the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR
+(Postfix version 2.1 and later only).  If no "\fI=d.d.d.d\fR" is
+specified, reject the request when the HELO or EHLO hostname is
+listed with any A record under \fIrbl_domain\fR. See the
+reject_rbl_client description for additional RBL related configuration
+parameters.  This feature is available in Postfix 2.0 and later.
 .IP "\fBreject_unknown_helo_hostname\fR (with Postfix < 2.3: reject_unknown_hostname)"
 Reject the request when the HELO or EHLO hostname has no DNS A
 or MX record.
index 24798cb0538f249ddbf5cc8c56e5ee9a5677a6c0..412c3e1eb0354b6e39e8f91cd93d2ce76cdc342b 100644 (file)
@@ -179,6 +179,11 @@ filter) applications after an unknown SMTP command.
 .IP "\fBmilter_end_of_data_macros (see postconf -n output)\fR"
 The macros that are sent to Milter (mail filter) applications
 after the message end-of-data.
+.PP
+Available in Postfix version 2.5 and later:
+.IP "\fBmilter_end_of_header_macros (see postconf -n output)\fR"
+The macros that are sent to Milter (mail filter) applications
+after the end of the message header.
 .SH "MIME PROCESSING CONTROLS"
 .na
 .nf
index 595354b06fed3381f50cd1708adf0be1b0a34427..565c1e65e67056089fab4f7e383d4918889943f1 100644 (file)
@@ -233,6 +233,9 @@ filter) applications after the SMTP DATA command.
 .IP "\fBmilter_unknown_command_macros (see postconf -n output)\fR"
 The macros that are sent to version 3 or higher Milter (mail
 filter) applications after an unknown SMTP command.
+.IP "\fBmilter_end_of_header_macros (see postconf -n output)\fR"
+The macros that are sent to Milter (mail filter) applications
+after the message header.
 .IP "\fBmilter_end_of_data_macros (see postconf -n output)\fR"
 The macros that are sent to Milter (mail filter) applications
 after the message end-of-data.
index 1588b5119807df6179e69e81fb64184b4eeb59d7..289ffcb731a15d9da26564987590c9c90ebcf81e 100755 (executable)
@@ -768,6 +768,7 @@ while (<>) {
     s;\breject_invalid_hostname\b;<a href="postconf.5.html#reject_invalid_helo_hostname">$&</a>;g;
     s;\breject_non_fqdn_helo_hostname\b;<a href="postconf.5.html#reject_non_fqdn_helo_hostname">$&</a>;g;
     s;\breject_non_fqdn_hostname\b;<a href="postconf.5.html#reject_non_fqdn_helo_hostname">$&</a>;g;
+    s;\breject_rhsbl_helo\b;<a href="postconf.5.html#reject_rhsbl_helo">$&</a>;g;
     s;\breject_unknown_helo_hostname\b;<a href="postconf.5.html#reject_unknown_helo_hostname">$&</a>;g;
     s;\breject_unknown_hostname\b;<a href="postconf.5.html#reject_unknown_helo_hostname">$&</a>;g;
 
@@ -817,6 +818,7 @@ while (<>) {
     s;\bmilter_data_macros\b;<a href="postconf.5.html#milter_data_macros">$&</a>;g;
     s;\bmilter_unknown_command_macros\b;<a href="postconf.5.html#milter_unknown_command_macros">$&</a>;g;
     s;\bmilter_end_of_data_macros\b;<a href="postconf.5.html#milter_end_of_data_macros">$&</a>;g;
+    s;\bmilter_end_of_header_macros\b;<a href="postconf.5.html#milter_end_of_header_macros">$&</a>;g;
 
     # Hyperlink URLs and RFC documents
 
index a2867504120ed4d1968faa300ee0c0892a9acca3..7176fc970da415a49b4601f24e5ef2c494aaa325 100644 (file)
@@ -429,6 +429,7 @@ not exist, and "reject" to reject mail with a permanent status.
 
 <blockquote>
 <pre>
+/etc/postfix/main.cf:
     # What to do in case of errors? Specify accept, reject, or tempfail.
     milter_default_action = tempfail
 </pre>
@@ -438,11 +439,13 @@ not exist, and "reject" to reject mail with a permanent status.
 
 <p> As Postfix is not built with the Sendmail libmilter library,
 you may need to configure the Milter protocol version that Postfix
-should use.  The default version is 2. </p>
+should use.  The default version is 2. Other protocol versions are
+3 and 4 (Postfix 2.3 and later), and 6 (Postfix 2.5 an later).  </p>
 
 <blockquote>
 <pre>
-milter_protocol = 2
+/etc/postfix/main.cf:
+    milter_protocol = 2
 </pre>
 </blockquote>
 
@@ -510,7 +513,8 @@ times. This is an inherent problem with before-queue filtering. </p>
 
 <p> Postfix emulates a limited number of Sendmail macros, as shown
 in the table. Different macros are available at different SMTP
-protocol stages (EOM = end-of-message); their availability is not
+protocol stages (EOH = end-of-header, EOM = end-of-message); their
+availability is not
 always the same as in Sendmail. See the <a
 href="#workarounds">workarounds</a> section below for solutions.
 </p>
@@ -522,7 +526,7 @@ href="#workarounds">workarounds</a> section below for solutions.
 <tr> <th> Name </th> <th> Availability </th> <th> Description </th>
 </tr>
 
-<tr> <td> i </td> <td> DATA, EOM </td> <td> Queue ID </td> </tr>
+<tr> <td> i </td> <td> DATA, EOH, EOM </td> <td> Queue ID </td> </tr>
 
 <tr> <td> j </td> <td> Always </td> <td> value of myhostname </td>
 </tr>
@@ -530,13 +534,13 @@ href="#workarounds">workarounds</a> section below for solutions.
 <tr> <td> _ </td> <td> Always </td> <td> The validated client name
 and address </td> </tr>
 
-<tr> <td> {auth_authen} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_authen} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 login name </td> </tr>
 
-<tr> <td> {auth_author} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_author} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 sender </td> </tr>
 
-<tr> <td> {auth_type} </td> <td> MAIL, DATA, EOM </td> <td> SASL
+<tr> <td> {auth_type} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
 login method </td> </tr>
 
 <tr> <td> {client_addr} </td> <td> Always </td> <td> Client IP
@@ -555,16 +559,16 @@ Connection concurrency for this client </td> </tr>
 <td> Client name from reverse lookup, "unknown" when lookup fails
 </td> </tr>
 
-<tr> <td> {cert_issuer} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {cert_issuer} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS client certificate issuer </td> </tr>
 
-<tr> <td> {cert_subject} </td> <td> HELO, MAIL, DATA, EOM </td>
+<tr> <td> {cert_subject} </td> <td> HELO, MAIL, DATA, EOH, EOM </td>
 <td> TLS client certificate subject </td> </tr>
 
-<tr> <td> {cipher_bits} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {cipher_bits} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS session key size </td> </tr>
 
-<tr> <td> {cipher} </td> <td> HELO, MAIL, DATA, EOM </td> <td> TLS
+<tr> <td> {cipher} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td> TLS
 cipher </td> </tr>
 
 <tr> <td> {daemon_name} </td> <td> Always </td> <td> value of
@@ -576,7 +580,7 @@ milter_macro_daemon_name </td> </tr>
 <tr> <td> {rcpt_addr} </td> <td> RCPT </td> <td> Recipient address
 </td> </tr>
 
-<tr> <td> {tls_version} </td> <td> HELO, MAIL, DATA, EOM </td> <td>
+<tr> <td> {tls_version} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
 TLS protocol version </td> </tr>
 
 <tr> <td> v </td> <td> Always </td> <td> value of milter_macro_v
@@ -588,7 +592,7 @@ TLS protocol version </td> </tr>
 
 <p> Postfix sends specific sets of macros at different SMTP protocol
 stages.  The sets are configured with the parameters as described
-in the table (EOM = end of message). </p>
+in the table (EOH = end of headers; EOM = end of message). </p>
 
 <blockquote>
 
@@ -612,6 +616,9 @@ TO </td> </tr>
 <tr> <td> milter_data_macros </td> <td> 4 or higher </td> <td> DATA
 </td> </tr>
 
+<tr> <td> milter_end_of_header_macros </td> <td> 6 or higher </td>
+<td> EOH </td> </tr>
+
 <tr> <td> milter_end_of_data_macros </td> <td> 2 or higher </td>
 <td> EOM </td> </tr>
 
@@ -765,9 +772,11 @@ a discussion. </p>
 
 <ul>
 
-<li> <p> Postfix currently supports only applications that speak
-the Sendmail 8 Milter protocol versions 2..4. Support for other
-protocol types or protocol versions may be added later. </p>
+<li> <p> Postfix version 2.3 introduces support for Sendmail 8
+milter protocol versions 2, 3 and 4; Postfix version 2.5 adds support
+for protocol version 6, which is available with Sendmail 8.14.
+Support for other protocol types or protocol versions may be added
+later. </p>
 
 <li> <p> For applications that are written in C, you need to use
 the Sendmail libmilter library. A Postfix replacement may be 
@@ -812,6 +821,12 @@ operation will log a warning like this: </p>
 
 <p> The solution is to use Postfix version 2.4 or later. </p>
 
+<li> <p> Postfix version 2.5 implements the Sendmail 8.14 features
+except: SMFIP_RCPT_REJ (report rejected recipients to the mail
+filter), SMFIR_CHGFROM (replace sender, with optional ESMTP command
+parameters), and SMFIR_ADDRCPT_PAR (add recipient, with optional
+ESMTP command parameters).
+
 <li> <p> Most Milter configuration options are global. Future Postfix
 versions may support per-Milter timeouts, per-Milter error handling,
 etc. </p>
index 8016c28a813e57a433ccbbdebb4d4298ffdfded2..b05f1e7f557f29351cfc065b83560ef1cdee4d85 100644 (file)
@@ -5157,6 +5157,17 @@ fully-qualified domain form, as required by the RFC. <br> The
 non_fqdn_reject_code parameter specifies the response code to
 rejected requests (default: 504).</dd>
 
+<dt><b><a name="reject_rhsbl_helo">reject_rhsbl_helo <i>rbl_domain=d.d.d.d</i></a></b></dt>
+
+<dd>Reject the request when the HELO or EHLO hostname hostname is
+listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
+(Postfix version 2.1 and later only).  If no "<i>=d.d.d.d</i>" is
+specified, reject the request when the HELO or EHLO hostname is
+listed with any A record under <i>rbl_domain</i>. See the
+reject_rbl_client description for additional RBL related configuration
+parameters.  This feature is available in Postfix 2.0 and later.
+</dd>
+
 <dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix &lt; 2.3: reject_unknown_hostname)</dt>
 
 <dd>Reject the request when the HELO or EHLO hostname has no DNS A
@@ -10121,20 +10132,25 @@ for details.  </p>
 %PARAM milter_protocol 2
 
 <p> The mail filter protocol version and optional protocol extensions
-for communication with a Milter (mail filter) application. This
-information should match the protocol that is expected by the actual
-mail filter application.  </p>
+for communication with a Milter (mail filter) application. Postfix
+sends this version number during the initial protocol handshake.
+It should match the version number that is expected by the mail
+filter application (or by its Milter library).  </p>
 
 <p>Protocol versions: </p>
 
 <dl compact>
 
-<dt>2</dt> <dd>Use Sendmail 8 mail filter protocol version 2.</dd>
+<dt>2</dt> <dd>Use Sendmail 8 mail filter protocol version 2 (default
+as of Sendmail version 8.11).</dd>
 
 <dt>3</dt> <dd>Use Sendmail 8 mail filter protocol version 3.</dd>
 
 <dt>4</dt> <dd>Use Sendmail 8 mail filter protocol version 4.</dd>
 
+<dt>6</dt> <dd>Use Sendmail 8 mail filter protocol version 6 (default
+as of Sendmail version 8.14).</dd>
+
 </dl>
 
 <p>Protocol extensions: </p>
@@ -10248,6 +10264,14 @@ for a list of available macro names and their meanings.  </p>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
+%PARAM milter_end_of_header_macros see postconf -n output
+
+<p> The macros that are sent to Milter (mail filter) applications
+after the end of the message header. See MILTER_README for a list
+of available macro names and their meanings.  </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
 %PARAM milter_end_of_data_macros see postconf -n output
 
 <p> The macros that are sent to Milter (mail filter) applications
index 1ce24302f5f04e308b13e24eff77705e88a2c9cf..577aa0a032c5bef5c784c760e387f5d0e93eafb3 100644 (file)
 /* .IP "\fBmilter_end_of_data_macros (see postconf -n output)\fR"
 /*     The macros that are sent to Milter (mail filter) applications
 /*     after the message end-of-data.
+/* .PP
+/*     Available in Postfix version 2.5 and later:
+/* .IP "\fBmilter_end_of_header_macros (see postconf -n output)\fR"
+/*     The macros that are sent to Milter (mail filter) applications
+/*     after the end of the message header.
 /* MIME PROCESSING CONTROLS
 /* .ad
 /* .fi
index ebbcb5461c7b71b4be4e213a07d8759402096fda..c30c91e9cb7b9d3797cc0362944f396ea176efe5 100644 (file)
@@ -157,6 +157,7 @@ char   *var_milt_helo_macros;               /* HELO macros */
 char   *var_milt_mail_macros;          /* MAIL FROM macros */
 char   *var_milt_rcpt_macros;          /* RCPT TO macros */
 char   *var_milt_data_macros;          /* DATA macros */
+char   *var_milt_eoh_macros;           /* end-of-header macros */
 char   *var_milt_eod_macros;           /* end-of-data macros */
 char   *var_milt_unk_macros;           /* unknown command macros */
 char   *var_cleanup_milters;           /* non-SMTP mail */
@@ -220,6 +221,7 @@ CONFIG_STR_TABLE cleanup_str_table[] = {
     VAR_MILT_MAIL_MACROS, DEF_MILT_MAIL_MACROS, &var_milt_mail_macros, 0, 0,
     VAR_MILT_RCPT_MACROS, DEF_MILT_RCPT_MACROS, &var_milt_rcpt_macros, 0, 0,
     VAR_MILT_DATA_MACROS, DEF_MILT_DATA_MACROS, &var_milt_data_macros, 0, 0,
+    VAR_MILT_EOH_MACROS, DEF_MILT_EOH_MACROS, &var_milt_eoh_macros, 0, 0,
     VAR_MILT_EOD_MACROS, DEF_MILT_EOD_MACROS, &var_milt_eod_macros, 0, 0,
     VAR_MILT_UNK_MACROS, DEF_MILT_UNK_MACROS, &var_milt_unk_macros, 0, 0,
     VAR_CLEANUP_MILTERS, DEF_CLEANUP_MILTERS, &var_cleanup_milters, 0, 0,
@@ -394,6 +396,7 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
                                        var_milt_mail_macros,
                                        var_milt_rcpt_macros,
                                        var_milt_data_macros,
+                                       var_milt_eoh_macros,
                                        var_milt_eod_macros,
                                        var_milt_unk_macros);
 
index e4e575c72833205e9920312b4c28d75e0ef98b37..8b9a81b770a9825eac39c717df88a7d9a03e3d20 100644 (file)
@@ -256,7 +256,9 @@ static const char *cleanup_milter_error(CLEANUP_STATE *state, int err)
 
 /* cleanup_add_header - append message header */
 
-static const char *cleanup_add_header(void *context, char *name, char *value)
+static const char *cleanup_add_header(void *context, const char *name,
+                                             const char *space,
+                                             const char *value)
 {
     const char *myname = "cleanup_add_header";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -286,7 +288,7 @@ static const char *cleanup_add_header(void *context, char *name, char *value)
        return (cleanup_milter_error(state, errno));
     }
     buf = vstring_alloc(100);
-    vstring_sprintf(buf, "%s: %s", name, value);
+    vstring_sprintf(buf, "%s:%s%s", name, space, value);
     cleanup_out_header(state, buf);            /* Includes padding */
     vstring_free(buf);
     if ((reverse_ptr_offset = vstream_ftell(state->dst)) < 0) {
@@ -600,6 +602,7 @@ static off_t cleanup_find_header_end(CLEANUP_STATE *state,
 
 static const char *cleanup_patch_header(CLEANUP_STATE *state,
                                                const char *new_hdr_name,
+                                               const char *hdr_space,
                                                const char *new_hdr_value,
                                                off_t old_rec_offset,
                                                int old_rec_type,
@@ -648,7 +651,7 @@ static const char *cleanup_patch_header(CLEANUP_STATE *state,
        msg_warn("%s: seek file %s: %m", myname, cleanup_path);
        CLEANUP_PATCH_HEADER_RETURN(cleanup_milter_error(state, errno));
     }
-    vstring_sprintf(buf, "%s: %s", new_hdr_name, new_hdr_value);
+    vstring_sprintf(buf, "%s:%s%s", new_hdr_name, hdr_space, new_hdr_value);
     cleanup_out_header(state, buf);            /* Includes padding */
     if (msg_verbose > 1)
        msg_info("%s: %ld: write %.*s", myname, (long) new_hdr_offset,
@@ -714,8 +717,9 @@ static const char *cleanup_patch_header(CLEANUP_STATE *state,
 /* cleanup_ins_header - insert message header */
 
 static const char *cleanup_ins_header(void *context, ssize_t index,
-                                             char *new_hdr_name,
-                                             char *new_hdr_value)
+                                             const char *new_hdr_name,
+                                             const char *hdr_space,
+                                             const char *new_hdr_value)
 {
     const char *myname = "cleanup_ins_header";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -763,7 +767,7 @@ static const char *cleanup_ins_header(void *context, ssize_t index,
      */
     if (old_rec_offset < 0)
        CLEANUP_INS_HEADER_RETURN(cleanup_add_header(context, new_hdr_name,
-                                                    new_hdr_value));
+                                                hdr_space, new_hdr_value));
 
     /*
      * If the header does exist, save both the new and the existing header to
@@ -779,7 +783,7 @@ static const char *cleanup_ins_header(void *context, ssize_t index,
            CLEANUP_INS_HEADER_RETURN(cleanup_milter_error(state, errno));
        }
     }
-    ret = cleanup_patch_header(state, new_hdr_name, new_hdr_value,
+    ret = cleanup_patch_header(state, new_hdr_name, hdr_space, new_hdr_value,
                               old_rec_offset, old_rec_type,
                               old_rec_buf, next_offset);
     CLEANUP_INS_HEADER_RETURN(ret);
@@ -788,8 +792,9 @@ static const char *cleanup_ins_header(void *context, ssize_t index,
 /* cleanup_upd_header - modify or append message header */
 
 static const char *cleanup_upd_header(void *context, ssize_t index,
-                                             char *new_hdr_name,
-                                             char *new_hdr_value)
+                                             const char *new_hdr_name,
+                                             const char *hdr_space,
+                                             const char *new_hdr_value)
 {
     const char *myname = "cleanup_upd_header";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -843,7 +848,7 @@ static const char *cleanup_upd_header(void *context, ssize_t index,
      */
     if (old_rec_offset < 0)
        CLEANUP_UPD_HEADER_RETURN(cleanup_add_header(context, new_hdr_name,
-                                                    new_hdr_value));
+                                                hdr_space, new_hdr_value));
 
     /*
      * If the old header is found, find the end of the old header, save the
@@ -853,7 +858,7 @@ static const char *cleanup_upd_header(void *context, ssize_t index,
     if ((next_offset = cleanup_find_header_end(state, rec_buf, last_type)) < 0)
        /* Warning and errno->error mapping are done elsewhere. */
        CLEANUP_UPD_HEADER_RETURN(cleanup_milter_error(state, 0));
-    ret = cleanup_patch_header(state, new_hdr_name, new_hdr_value,
+    ret = cleanup_patch_header(state, new_hdr_name, hdr_space, new_hdr_value,
                               old_rec_offset, DONT_SAVE_RECORD,
                               (VSTRING *) 0, next_offset);
     CLEANUP_UPD_HEADER_RETURN(ret);
@@ -862,7 +867,7 @@ static const char *cleanup_upd_header(void *context, ssize_t index,
 /* cleanup_del_header - delete message header */
 
 static const char *cleanup_del_header(void *context, ssize_t index,
-                                             char *hdr_name)
+                                             const char *hdr_name)
 {
     const char *myname = "cleanup_del_header";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -928,7 +933,7 @@ static const char *cleanup_del_header(void *context, ssize_t index,
 
 /* cleanup_add_rcpt - append recipient address */
 
-static const char *cleanup_add_rcpt(void *context, char *ext_rcpt)
+static const char *cleanup_add_rcpt(void *context, const char *ext_rcpt)
 {
     const char *myname = "cleanup_add_rcpt";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -1034,7 +1039,7 @@ static const char *cleanup_add_rcpt(void *context, char *ext_rcpt)
 
 /* cleanup_del_rcpt - remove recipient and all its expansions */
 
-static const char *cleanup_del_rcpt(void *context, char *ext_rcpt)
+static const char *cleanup_del_rcpt(void *context, const char *ext_rcpt)
 {
     const char *myname = "cleanup_del_rcpt";
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -1325,6 +1330,8 @@ void    cleanup_milter_receive(CLEANUP_STATE *state, int count)
     if (state->milters)
        milter_free(state->milters);
     state->milters = milter_receive(state->src, count);
+    if (state->milters == 0)
+       msg_fatal("cleanup_milter_receive: milter receive failed");
     milter_macro_callback(state->milters, cleanup_milter_eval, (void *) state);
     milter_edit_callback(state->milters,
                         cleanup_add_header, cleanup_upd_header,
@@ -1853,7 +1860,7 @@ int     main(int unused_argc, char **argv)
                msg_warn("bad add_header argument count: %d", argv->argc);
            } else {
                flatten_args(arg_buf, argv->argv + 2);
-               cleanup_add_header(state, argv->argv[1], STR(arg_buf));
+               cleanup_add_header(state, argv->argv[1], " ", STR(arg_buf));
            }
        } else if (strcmp(argv->argv[0], "ins_header") == 0) {
            if (argv->argc < 3) {
@@ -1862,7 +1869,7 @@ int     main(int unused_argc, char **argv)
                msg_warn("bad ins_header index value");
            } else {
                flatten_args(arg_buf, argv->argv + 3);
-               cleanup_ins_header(state, index, argv->argv[2], STR(arg_buf));
+               cleanup_ins_header(state, index, argv->argv[2], " ", STR(arg_buf));
            }
        } else if (strcmp(argv->argv[0], "upd_header") == 0) {
            if (argv->argc < 3) {
@@ -1871,7 +1878,7 @@ int     main(int unused_argc, char **argv)
                msg_warn("bad upd_header index value");
            } else {
                flatten_args(arg_buf, argv->argv + 3);
-               cleanup_upd_header(state, index, argv->argv[2], STR(arg_buf));
+               cleanup_upd_header(state, index, argv->argv[2], " ", STR(arg_buf));
            }
        } else if (strcmp(argv->argv[0], "del_header") == 0) {
            if (argv->argc != 3) {
index 88fb115d4ad3cc0e281112fcbb325412d2a8a6f7..549ebc224e715121290013c2a682aba34680a80a 100644 (file)
@@ -2770,6 +2770,10 @@ extern char *var_milt_data_macros;
 #define DEF_MILT_UNK_MACROS            ""
 extern char *var_milt_unk_macros;
 
+#define VAR_MILT_EOH_MACROS            "milter_end_of_header_macros"
+#define DEF_MILT_EOH_MACROS            "i"
+extern char *var_milt_eoh_macros;
+
 #define VAR_MILT_EOD_MACROS            "milter_end_of_data_macros"
 #define DEF_MILT_EOD_MACROS            "i"
 extern char *var_milt_eod_macros;
index 0e5accec6947b9157cfe5584b58189a74e7e5736..993237c640c02772c28705e6ba04a26e12bd54a6 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20071218"
+#define MAIL_RELEASE_DATE      "20071221"
 #define MAIL_VERSION_NUMBER    "2.5"
 
 #ifdef SNAPSHOT
index ce66bd170376c91ce7cdff7e3756f7d421215505..3aba2663521ff8deeb0ace39ed3be2174cd55cbf 100644 (file)
@@ -67,7 +67,7 @@ milter:       milter.c $(LIB) $(LIBS)
        mv junk $@.o
 
 test-milter: test-milter.c
-       cc -g -o $@ $? -lmilter -lpthread
+       cc -g -I/usr/local/include -o $@ $? -L/usr/local/lib -lmilter -lpthread
 
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
index 2e0c73128459f304fd99077b0fa218399d7918d6..e9024f721474219b03cbc6fc8a81e4de1ee02393 100644 (file)
@@ -10,8 +10,8 @@
 /*                                     msg_timeout, protocol, def_action,
 /*                                     conn_macros, helo_macros,
 /*                                     mail_macros, rcpt_macros,
-/*                                     data_macros, eod_macros,
-/*                                     unk_macros)
+/*                                     data_macros, eoh_macros,
+/*                                     eod_macros, unk_macros)
 /*     const char *milter_names;
 /*     int     conn_timeout;
 /*     int     cmd_timeout;
@@ -23,6 +23,7 @@
 /*     const char *mail_macros;
 /*     const char *rcpt_macrps;
 /*     const char *data_macros;
+/*     const char *eoh_macros;
 /*     const char *eod_macros;
 /*     const char *unk_macros;
 /*
 /*                                     ins_header, del_header, add_rcpt,
 /*                                     del_rcpt, repl_body, context)
 /*     MILTERS *milters;
-/*     const char *(*add_header) (void *context, char *name, char *value);
-/*     const char *(*upd_header) (void *context, ssize_t index,
-/*                             char *name, char *value);
-/*     const char *(*ins_header) (void *context, ssize_t index,
-/*                             char *name, char *value);
-/*     const char *(*del_header) (void *context, ssize_t index, char *name);
-/*     const char *(*add_rcpt) (void *context, char *rcpt);
-/*     const char *(*del_rcpt) (void *context, char *rcpt);
-/*     const char *(*repl_body) (void *context, VSTRING *body);
+/*     MILTER_ADD_HEADER_FN add_header;
+/*     MILTER_EDIT_HEADER_FN upd_header;
+/*     MILTER_EDIT_HEADER_FN ins_header;
+/*     MILTER_DEL_HEADER_FN del_header;
+/*     MILTER_EDIT_RCPT_FN add_rcpt;
+/*     MILTER_EDIT_RCPT_FN del_rcpt;
+/*     MILTER_EDIT_BODY_FN repl_body;
 /*     void    *context;
 /*
 /*     const char *milter_conn_event(milters, client_name, client_addr,
 /*
 /*     milter_message() sends the message header and body to the
 /*     to the specified milter instances, and sends the macros
-/*     specified with the milter_create() eod_macros argument at
+/*     specified with the milter_create() eoh_macros after the
+/*     message header, and with the eod_macros argument at
 /*     the end.  Each milter sees the result of any changes made
 /*     by a preceding milter. This function must be called with
 /*     as argument an open Postfix queue file.
@@ -281,13 +281,13 @@ void    milter_macro_callback(MILTERS *milters,
 /* milter_edit_callback - specify queue file edit call-back information */
 
 void    milter_edit_callback(MILTERS *milters,
-                        const char *(*add_header) (void *, char *, char *),
-               const char *(*upd_header) (void *, ssize_t, char *, char *),
-               const char *(*ins_header) (void *, ssize_t, char *, char *),
-                       const char *(*del_header) (void *, ssize_t, char *),
-                                  const char *(*add_rcpt) (void *, char *),
-                                  const char *(*del_rcpt) (void *, char *),
-                         const char *(*repl_body) (void *, int, VSTRING *),
+                                    MILTER_ADD_HEADER_FN add_header,
+                                    MILTER_EDIT_HEADER_FN upd_header,
+                                    MILTER_EDIT_HEADER_FN ins_header,
+                                    MILTER_DEL_HEADER_FN del_header,
+                                    MILTER_EDIT_RCPT_FN add_rcpt,
+                                    MILTER_EDIT_RCPT_FN del_rcpt,
+                                    MILTER_EDIT_BODY_FN repl_body,
                                     void *chg_context)
 {
     milters->add_header = add_header;
@@ -454,16 +454,21 @@ const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset)
 {
     const char *resp;
     MILTER *m;
-    ARGV   *macros;
+    ARGV   *eoh_macros;
+    ARGV   *eod_macros;
 
     if (msg_verbose)
        msg_info("inspect content by all milters");
-    macros = milters->eod_macros == 0 ? 0 :
+    eoh_macros = milters->eoh_macros == 0 ? 0 :
+       milter_macro_lookup(milters, milters->eoh_macros);
+    eod_macros = milters->eod_macros == 0 ? 0 :
        milter_macro_lookup(milters, milters->eod_macros);
     for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
-       resp = m->message(m, fp, data_offset, macros);
-    if (macros)
-       argv_free(macros);
+       resp = m->message(m, fp, data_offset, eoh_macros, eod_macros);
+    if (eoh_macros)
+       argv_free(eoh_macros);
+    if (eod_macros)
+       argv_free(eod_macros);
     return (resp);
 }
 
@@ -504,6 +509,7 @@ MILTERS *milter_create(const char *names,
                               const char *mail_macros,
                               const char *rcpt_macros,
                               const char *data_macros,
+                              const char *eoh_macros,
                               const char *eod_macros,
                               const char *unk_macros)
 {
@@ -543,12 +549,14 @@ MILTERS *milter_create(const char *names,
     milters->mail_macros = mystrdup(mail_macros);
     milters->rcpt_macros = mystrdup(rcpt_macros);
     milters->data_macros = mystrdup(data_macros);
+    milters->eoh_macros = mystrdup(eoh_macros);
     milters->eod_macros = mystrdup(eod_macros);
     milters->unk_macros = mystrdup(unk_macros);
     milters->add_header = 0;
     milters->upd_header = milters->ins_header = 0;
     milters->del_header = 0;
     milters->add_rcpt = milters->del_rcpt = 0;
+    milters->repl_body = 0;
     milters->chg_context = 0;
     return (milters);
 }
@@ -574,6 +582,8 @@ void    milter_free(MILTERS *milters)
        myfree(milters->rcpt_macros);
     if (milters->rcpt_macros)
        myfree(milters->data_macros);
+    if (milters->eoh_macros)
+       myfree(milters->eoh_macros);
     if (milters->eod_macros)
        myfree(milters->eod_macros);
     if (milters->unk_macros)
@@ -591,6 +601,7 @@ void    milter_free(MILTERS *milters)
 #define MAIL_ATTR_MILT_MAIL    "mail_macros"
 #define MAIL_ATTR_MILT_RCPT    "rcpt_macros"
 #define MAIL_ATTR_MILT_DATA    "data_macros"
+#define MAIL_ATTR_MILT_EOH     "eoh_macros"
 #define MAIL_ATTR_MILT_EOD     "eod_macros"
 #define MAIL_ATTR_MILT_UNK     "unk_macros"
 
@@ -634,6 +645,7 @@ int     milter_send(MILTERS *milters, VSTREAM *stream)
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, milters->mail_macros,
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, milters->rcpt_macros,
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, milters->data_macros,
+                     ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, milters->eoh_macros,
                      ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, milters->eod_macros,
                      ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, milters->unk_macros,
                      ATTR_TYPE_END);
@@ -668,6 +680,7 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
     VSTRING *mail_macros;
     VSTRING *rcpt_macros;
     VSTRING *data_macros;
+    VSTRING *eoh_macros;
     VSTRING *eod_macros;
     VSTRING *unk_macros;
 
@@ -677,8 +690,8 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
 #define FREE_BUFFERS() do { \
        vstring_free(conn_macros); vstring_free(helo_macros); \
        vstring_free(mail_macros); vstring_free(rcpt_macros); \
-       vstring_free(data_macros); vstring_free(eod_macros); \
-       vstring_free(unk_macros); \
+       vstring_free(data_macros); vstring_free(eoh_macros); \
+       vstring_free(eod_macros); vstring_free(unk_macros); \
    } while (0)
 
     conn_macros = vstring_alloc(10);
@@ -686,6 +699,7 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
     mail_macros = vstring_alloc(10);
     rcpt_macros = vstring_alloc(10);
     data_macros = vstring_alloc(10);
+    eoh_macros = vstring_alloc(10);
     eod_macros = vstring_alloc(10);
     unk_macros = vstring_alloc(10);
     if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
@@ -694,9 +708,10 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, mail_macros,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, rcpt_macros,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, data_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, eoh_macros,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, eod_macros,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, unk_macros,
-                 ATTR_TYPE_END) != 7) {
+                 ATTR_TYPE_END) != 8) {
        FREE_BUFFERS();
        return (0);
     }
@@ -708,8 +723,8 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
     milters = milter_create(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION,
                            STR(conn_macros), STR(helo_macros),
                            STR(mail_macros), STR(rcpt_macros),
-                           STR(data_macros), STR(eod_macros),
-                           STR(unk_macros));
+                           STR(data_macros), STR(eoh_macros),
+                           STR(eod_macros), STR(unk_macros));
     FREE_BUFFERS();
 
     /*
@@ -794,7 +809,7 @@ int     main(int argc, char **argv)
 {
     MILTERS *milters = 0;
     char   *conn_macros, *helo_macros, *mail_macros, *rcpt_macros;
-    char   *data_macros, *eod_macros, *unk_macros;
+    char   *data_macros, *eoh_macros, *eod_macros, *unk_macros;
     VSTRING *inbuf = vstring_alloc(100);
     char   *bufp;
     char   *cmd;
@@ -802,7 +817,7 @@ int     main(int argc, char **argv)
     int     istty = isatty(vstream_fileno(VSTREAM_IN));
 
     conn_macros = helo_macros = mail_macros = rcpt_macros = data_macros
-       = eod_macros = unk_macros = "";
+       = eoh_macros = eod_macros = unk_macros = "";
 
     msg_vstream_init(argv[0], VSTREAM_ERR);
     while ((ch = GETOPT(argc, argv, "V:v")) > 0) {
@@ -856,8 +871,8 @@ int     main(int argc, char **argv)
                                    var_milt_cmd_time, var_milt_msg_time,
                                    var_milt_protocol, var_milt_def_action,
                                    conn_macros, helo_macros, mail_macros,
-                                   rcpt_macros, data_macros, eod_macros,
-                                   unk_macros);
+                                   rcpt_macros, data_macros, eoh_macros,
+                                   eod_macros, unk_macros);
        } else if (strcmp(cmd, "free") == 0 && argv->argc == 0) {
            if (milters == 0) {
                msg_warn("no milters");
index b29fff511d468ade5de8805065441825a642ea9f..b47efb95978498ce3f547850742d3c93882c15dc 100644 (file)
@@ -33,7 +33,7 @@ typedef struct MILTER {
     const char *(*mail_event) (struct MILTER *, const char **, ARGV *);
     const char *(*rcpt_event) (struct MILTER *, const char **, ARGV *);
     const char *(*data_event) (struct MILTER *, ARGV *);
-    const char *(*message) (struct MILTER *, VSTREAM *, off_t, ARGV *);
+    const char *(*message) (struct MILTER *, VSTREAM *, off_t, ARGV *, ARGV *);
     const char *(*unknown_event) (struct MILTER *, const char *, ARGV *);
     const char *(*other_event) (struct MILTER *);
     void    (*abort) (struct MILTER *);
@@ -49,40 +49,41 @@ extern MILTER *milter8_receive(VSTREAM *, struct MILTERS *);
  /*
   * A bunch of Milters.
   */
+typedef const char *(*MILTER_MAC_LOOKUP_FN) (const char *, void *);
+typedef const char *(*MILTER_ADD_HEADER_FN) (void *, const char *, const char *, const char *);
+typedef const char *(*MILTER_EDIT_HEADER_FN) (void *, ssize_t, const char *, const char *, const char *);
+typedef const char *(*MILTER_DEL_HEADER_FN) (void *, ssize_t, const char *);
+typedef const char *(*MILTER_EDIT_RCPT_FN) (void *, const char *);
+typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, VSTRING *);
+
 typedef struct MILTERS {
     MILTER *milter_list;               /* linked list of Milters */
-    const char *(*mac_lookup) (const char *, void *);
+    MILTER_MAC_LOOKUP_FN mac_lookup;
     void   *mac_context;               /* macro lookup context */
     char   *conn_macros;               /* macros for connect event */
     char   *helo_macros;               /* macros for HELO/EHLO command */
     char   *mail_macros;               /* macros for MAIL FROM command */
     char   *rcpt_macros;               /* macros for RCPT TO command */
     char   *data_macros;               /* macros for DATA command */
+    char   *eoh_macros;                        /* macros for end-of-headers */
     char   *eod_macros;                        /* macros for END-OF-DATA command */
     char   *unk_macros;                        /* macros for unknown command */
     void   *chg_context;               /* context for queue file changes */
-    const char *(*add_header) (void *, char *, char *);
-    const char *(*upd_header) (void *, ssize_t, char *, char *);
-    const char *(*del_header) (void *, ssize_t, char *);
-    const char *(*ins_header) (void *, ssize_t, char *, char *);
-    const char *(*add_rcpt) (void *, char *);
-    const char *(*del_rcpt) (void *, char *);
-    const char *(*repl_body) (void *, int, VSTRING *);
+    MILTER_ADD_HEADER_FN add_header;
+    MILTER_EDIT_HEADER_FN upd_header;
+    MILTER_DEL_HEADER_FN del_header;
+    MILTER_EDIT_HEADER_FN ins_header;
+    MILTER_EDIT_RCPT_FN add_rcpt;
+    MILTER_EDIT_RCPT_FN del_rcpt;
+    MILTER_EDIT_BODY_FN repl_body;
 } MILTERS;
 
-typedef const char *(*MILTER_MAC_LOOKUP_FN) (const char *, void *);
-typedef const char *(*MILTER_ADD_HEADER_FN) (void *, char *, char *);
-typedef const char *(*MILTER_EDIT_HEADER_FN) (void *, ssize_t, char *, char *);
-typedef const char *(*MILTER_DEL_HEADER_FN) (void *, ssize_t, char *);
-typedef const char *(*MILTER_EDIT_RCPT_FN) (void *, char *);
-typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, VSTRING *);
-
 extern MILTERS *milter_create(const char *, int, int, int,
                                      const char *, const char *,
                                      const char *, const char *,
                                      const char *, const char *,
                                      const char *, const char *,
-                                     const char *);
+                                     const char *, const char *);
 extern void milter_macro_callback(MILTERS *, MILTER_MAC_LOOKUP_FN, void *);
 extern void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN,
                               MILTER_EDIT_HEADER_FN, MILTER_EDIT_HEADER_FN,
@@ -110,7 +111,7 @@ extern void milter_free(MILTERS *);
 #define MILTER_BODY_START      1       /* start message body */
 #define MILTER_BODY_LINE       2       /* message body line */
 #define MILTER_BODY_END                3       /* end message body */
-  
+
  /*
   * Sendmail 8 macro names. We support forms with and without the {}.
   */
index 7f7fbb64169191680a336ba45f2e371d395840cd..09437630f65c8730d6c7b8e02f76743a3c2cc8ec 100644 (file)
@@ -60,6 +60,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
+#include <stddef.h>                    /* offsetof() */
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #define SHUT_RDWR      2
 #endif
 
-/* Sendmail 8 Milter protocol. */
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <split_at.h>
+#include <connect.h>
+#include <argv.h>
+#include <name_mask.h>
+#include <name_code.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_params.h>               /* var_line_limit */
+#include <mail_proto.h>
+#include <rec_type.h>
+#include <record.h>
+#include <mime_state.h>
+#include <is_header.h>
+
+/* Postfix Milter library. */
+
+#include <milter.h>
+
+/* Application-specific. */
 
  /*
   * Use our own protocol definitions, so that Postfix can be built even when
   * libmilter is not installed. This means that we must specify the libmilter
-  * protocol version in main.cf. The other option (above) is to compile
-  * Postfix with the installed libmilter include files and to support only
-  * that protocol version.
+  * protocol version in main.cf, and that we must send only the commands that
+  * are supported for that protocol version.
   */
 
  /*
 #define SMFIC_RCPT             'R'     /* RCPT to */
 #define SMFIC_DATA             'T'     /* DATA */
 #define SMFIC_UNKNOWN          'U'     /* Any unknown command */
+ /* Introduced with Sendmail 8.14. */
+#define SMFIC_QUIT_NC          'K'     /* Quit + new connection */
 
  /*
   * Responses from filter to MTA.
 #define SMFIR_INSHEADER                'i'     /* insert header */
 #define SMFIR_REPLYCODE                'y'     /* reply code etc */
 #define SMFIR_QUARANTINE       'q'     /* quarantine */
+ /* Introduced with Sendmail 8.14. */
+#define SMFIR_SKIP             's'     /* skip further events of this type */
+#define SMFIR_CHGFROM          'e'     /* change sender (incl. ESMTP args) */
+#define SMFIR_ADDRCPT_PAR      '2'     /* add recipient (incl. ESMTP args) */
+#define SMFIR_SETSYMLIST       'l'     /* set list of symbols (macros) */
 
  /*
   * Commands that the filter does not want to receive, and replies that the
-  * filter will not send.
+  * filter will not send. Plus some other random stuff.
   */
-#define SMFIP_NOCONNECT                (1L<<0) /* MTA should not send connect info */
-#define SMFIP_NOHELO           (1L<<1) /* MTA should not send HELO info */
-#define SMFIP_NOMAIL           (1L<<2) /* MTA should not send MAIL info */
-#define SMFIP_NORCPT           (1L<<3) /* MTA should not send RCPT info */
-#define SMFIP_NOBODY           (1L<<4) /* MTA should not send body */
-#define SMFIP_NOHDRS           (1L<<5) /* MTA should not send headers */
-#define SMFIP_NOEOH            (1L<<6) /* MTA should not send EOH */
-#define SMFIP_NOHREPL          (1L<<7) /* filter will not reply per header */
-#define SMFIP_NOUNKNOWN        (1L<<8) /* MTA should not send unknown cmd */
-#define SMFIP_NODATA           (1L<<9) /* MTA should not send DATA */
+#define SMFIP_NOCONNECT                (1L<<0) /* filter does not want connect info */
+#define SMFIP_NOHELO           (1L<<1) /* filter does not want HELO info */
+#define SMFIP_NOMAIL           (1L<<2) /* filter does not want MAIL info */
+#define SMFIP_NORCPT           (1L<<3) /* filter does not want RCPT info */
+#define SMFIP_NOBODY           (1L<<4) /* filter does not want body */
+#define SMFIP_NOHDRS           (1L<<5) /* filter does not want headers */
+#define SMFIP_NOEOH            (1L<<6) /* filter does not want EOH */
+#define SMFIP_NR_HDR           (1L<<7) /* filter won't reply for header */
+#define SMFIP_NOHREPL          SMFIP_NR_HDR
+#define SMFIP_NOUNKNOWN        (1L<<8) /* filter does not want unknown cmd */
+#define SMFIP_NODATA           (1L<<9) /* filter does not want DATA */
+ /* Introduced with Sendmail 8.14. */
+#define SMFIP_SKIP             (1L<<10)/* MTA supports SMFIS_SKIP */
+#define SMFIP_RCPT_REJ         (1L<<11)/* filter wants rejected RCPTs */
+#define SMFIP_NR_CONN          (1L<<12)/* filter won't reply for connect */
+#define SMFIP_NR_HELO          (1L<<13)/* filter won't reply for HELO */
+#define SMFIP_NR_MAIL          (1L<<14)/* filter won't reply for MAIL */
+#define SMFIP_NR_RCPT          (1L<<15)/* filter won't reply for RCPT */
+#define SMFIP_NR_DATA          (1L<<16)/* filter won't reply for DATA */
+#define SMFIP_NR_UNKN          (1L<<17)/* filter won't reply for UNKNOWN */
+#define SMFIP_NR_EOH           (1L<<18)/* filter won't reply for eoh */
+#define SMFIP_NR_BODY          (1L<<19)/* filter won't reply for body chunk */
+#define SMFIP_HDR_LEADSPC      (1L<<20)/* header value has leading space */
+
+#define SMFIP_NOSEND_MASK \
+       (SMFIP_NOCONNECT | SMFIP_NOHELO | SMFIP_NOMAIL | SMFIP_NORCPT \
+       | SMFIP_NOBODY | SMFIP_NOHDRS | SMFIP_NOEOH | SMFIP_NOUNKNOWN \
+       | SMFIP_NODATA)
+
+#define SMFIP_NOREPLY_MASK \
+       (SMFIP_NR_CONN | SMFIP_NR_HELO | SMFIP_NR_MAIL | SMFIP_NR_RCPT \
+       | SMFIP_NR_DATA | SMFIP_NR_UNKN | SMFIP_NR_HDR | SMFIP_NR_EOH | \
+       SMFIP_NR_BODY)
 
  /*
-  * Modifications that the filter may request at the end of the message body.
+  * Options that the filter may send at initial handshake time, and message
+  * modifications that the filter may request at the end of the message body.
   */
 #define SMFIF_ADDHDRS          (1L<<0) /* filter may add headers */
 #define SMFIF_CHGBODY          (1L<<1) /* filter may replace body */
 #define SMFIF_DELRCPT          (1L<<3) /* filter may delete recipients */
 #define SMFIF_CHGHDRS          (1L<<4) /* filter may change/delete headers */
 #define SMFIF_QUARANTINE       (1L<<5) /* filter may quarantine envelope */
+ /* Introduced with Sendmail 8.14. */
+#define SMFIF_CHGFROM          (1L<<6) /* filter may replace sender */
+#define SMFIF_ADDRCPT_PAR      (1L<<7) /* filter may add recipients + args */
+#define SMFIF_SETSYMLIST       (1L<<8) /* filter may send macro names */
 
  /*
   * Network protocol families, used when sending CONNECT information.
 #define SMFIA_INET6            '6'     /* inet6 */
 
  /*
-  * How much buffer space is available for receiving body content.
+  * External macro set numbers, to identify the optional macro name lists
+  * that may be sent after the initial negotiation header.
   */
-#define MILTER_CHUNK_SIZE      65535   /* body chunk size */
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <split_at.h>
-#include <connect.h>
-#include <argv.h>
-#include <name_mask.h>
-#include <name_code.h>
-#include <stringops.h>
-
-/* Global library. */
-
-#include <mail_params.h>               /* var_line_limit */
-#include <mail_proto.h>
-#include <rec_type.h>
-#include <record.h>
-#include <mime_state.h>
-#include <is_header.h>
+#define SMFIM_FIRST    0
+#define SMFIM_CONNECT  0               /* macros for connect */
+#define SMFIM_HELO     1               /* macros for HELO */
+#define SMFIM_ENVFROM  2               /* macros for MAIL */
+#define SMFIM_ENVRCPT  3               /* macros for RCPT */
+#define SMFIM_DATA     4               /* macros for DATA */
+#define SMFIM_EOM      5               /* macros for end-of-message */
+#define SMFIM_EOH      6               /* macros for end-of-header */
+#define SMFIM_LAST     6
 
-/* Postfix Milter library. */
+ /*
+  * Mapping from external macro set numbers to our internal MILTERS structure
+  * members, without using a switch statement.
+  */
+static size_t milter8_macro_offsets[] = {
+    offsetof(MILTERS, conn_macros),    /* SMFIM_CONNECT */
+    offsetof(MILTERS, helo_macros),    /* SMFIM_HELO */
+    offsetof(MILTERS, mail_macros),    /* SMFIM_ENVFROM */
+    offsetof(MILTERS, rcpt_macros),    /* SMFIM_ENVRCPT */
+    offsetof(MILTERS, data_macros),    /* SMFIM_DATA */
+    offsetof(MILTERS, eod_macros),     /* Note: SMFIM_EOM < SMFIM_EOH */
+    offsetof(MILTERS, eoh_macros),     /* Note: SMFIM_EOH > SMFIM_EOM */
+};
 
-#include <milter.h>
+#define MILTER8_MACRO_PTR(__milters, __type) \
+       ((char **) (((char *) (__milters)) + milter8_macro_offsets[(__type)]))
 
-/* Application-specific. */
+ /*
+  * How much buffer space is available for sending body content.
+  */
+#define MILTER_CHUNK_SIZE      65535   /* body chunk size */
 
 /*#define msg_verbose 2*/
 
@@ -207,6 +271,7 @@ typedef struct {
      */
     int     state;                     /* MILTER8_STAT_mumble */
     char   *def_reply;                 /* error response or null */
+    int     skip_event_type;           /* skip operations of this type */
 } MILTER8;
 
  /*
@@ -243,6 +308,7 @@ typedef struct {
 #define MILTER8_DATA_NSHORT    4       /* network short */
 #define MILTER8_DATA_ARGV      5       /* array of null-terminated strings */
 #define MILTER8_DATA_OCTET     6       /* byte */
+#define MILTER8_DATA_MACROS    7       /* macro lists (receive-only) */
 
  /*
   * We don't accept insane amounts of data.
@@ -251,18 +317,28 @@ typedef struct {
 #define XXX_TIMEOUT    10
 
  /*
-  * If we're not using Sendmail's libmilter include files, then we implement
-  * the protocol up to and including version 4, and configure in main.cf what
-  * protocol version we will use. However, we must send only events that are
-  * defined for the specified protocol version, otherwise libmilter will
-  * disconnect.
+  * We implement the protocol up to and including version 6, and configure in
+  * main.cf what protocol version we will use. The version is the first data
+  * item in the SMFIC_OPTNEG packet.
   * 
-  * The following events are supported by all milter protocol implementations.
+  * We must send only events that are defined for the specified protocol
+  * version. Libmilter may disconnect when we send unexpected events.
+  * 
+  * The following events are supported in all our milter protocol versions.
   */
-#define MILTER8_V1_PROTO_MASK \
+#define MILTER8_V2_PROTO_MASK \
        (SMFIP_NOCONNECT | SMFIP_NOHELO | SMFIP_NOMAIL | SMFIP_NORCPT | \
        SMFIP_NOBODY | SMFIP_NOHDRS | SMFIP_NOEOH)
 
+ /*
+  * Events supported by later versions.
+  */
+#define MILTER8_V3_PROTO_MASK  (MILTER8_V2_PROTO_MASK | SMFIP_NOUNKNOWN)
+#define MILTER8_V4_PROTO_MASK  (MILTER8_V3_PROTO_MASK | SMFIP_NODATA)
+#define MILTER8_V6_PROTO_MASK \
+       (MILTER8_V4_PROTO_MASK | SMFIP_SKIP /* | SMFIP_RCPT_REJ */ \
+       | SMFIP_NOREPLY_MASK | SMFIP_HDR_LEADSPC)
+
  /*
   * What events we can send to the milter application. The milter8_protocol
   * parameter can specify a protocol version as well as protocol extensions
@@ -271,11 +347,15 @@ typedef struct {
   * 
   * This looks unclean because the user can specify multiple protocol versions,
   * but that is taken care of by the table that follows this one.
+  * 
+  * XXX Is this still needed? Sendmail 8.14 provides a proper way to negotiate
+  * what replies the mail filter will send.
   */
 static NAME_CODE milter8_event_masks[] = {
-    "2", MILTER8_V1_PROTO_MASK,
-    "3", MILTER8_V1_PROTO_MASK | SMFIP_NOUNKNOWN,
-    "4", MILTER8_V1_PROTO_MASK | SMFIP_NOUNKNOWN | SMFIP_NODATA,
+    "2", MILTER8_V2_PROTO_MASK,
+    "3", MILTER8_V3_PROTO_MASK,
+    "4", MILTER8_V4_PROTO_MASK,
+    "6", MILTER8_V6_PROTO_MASK,
     "no_header_reply", SMFIP_NOHREPL,
     0, -1,
 };
@@ -290,6 +370,7 @@ static NAME_CODE milter8_versions[] = {
     "2", 2,
     "3", 3,
     "4", 4,
+    "6", 6,
     "no_header_reply", 0,
     0, -1,
 };
@@ -311,12 +392,10 @@ static NAME_CODE smfic_table[] = {
     "SMFIC_OPTNEG", SMFIC_OPTNEG,
     "SMFIC_QUIT", SMFIC_QUIT,
     "SMFIC_RCPT", SMFIC_RCPT,
-#ifdef SMFIC_DATA
     "SMFIC_DATA", SMFIC_DATA,
-#endif
-#ifdef SMFIC_UNKNOWN
     "SMFIC_UNKNOWN", SMFIC_UNKNOWN,
-#endif
+    /* Introduced with Sendmail 8.14. */
+    "SMFIC_QUIT_NC", SMFIC_QUIT_NC,
     0, 0,
 };
 
@@ -327,26 +406,21 @@ static NAME_CODE smfir_table[] = {
     "SMFIR_REPLBODY", SMFIR_REPLBODY,
     "SMFIR_CONTINUE", SMFIR_CONTINUE,
     "SMFIR_DISCARD", SMFIR_DISCARD,
-#ifdef SMFIR_CONN_FAIL
     "SMFIR_CONN_FAIL", SMFIR_CONN_FAIL,
-#endif
-#ifdef SMFIR_CHGHEADER
     "SMFIR_CHGHEADER", SMFIR_CHGHEADER,
-#endif
     "SMFIR_PROGRESS", SMFIR_PROGRESS,
     "SMFIR_REJECT", SMFIR_REJECT,
     "SMFIR_TEMPFAIL", SMFIR_TEMPFAIL,
-#ifdef SMFIR_SHUTDOWN
     "SMFIR_SHUTDOWN", SMFIR_SHUTDOWN,
-#endif
     "SMFIR_ADDHEADER", SMFIR_ADDHEADER,
-#ifdef SMFIR_INSHEADER
     "SMFIR_INSHEADER", SMFIR_INSHEADER,
-#endif
     "SMFIR_REPLYCODE", SMFIR_REPLYCODE,
-#ifdef SMFIR_QUARANTINE
     "SMFIR_QUARANTINE", SMFIR_QUARANTINE,
-#endif
+    /* Introduced with Sendmail 8.14. */
+    "SMFIR_SKIP", SMFIR_SKIP,
+    "SMFIR_CHGFROM", SMFIR_CHGFROM,
+    "SMFIR_ADDRCPT_PAR", SMFIR_ADDRCPT_PAR,
+    "SMFIR_SETSYMLIST", SMFIR_SETSYMLIST,
     0, 0,
 };
 
@@ -358,15 +432,21 @@ static NAME_MASK smfip_table[] = {
     "SMFIP_NOBODY", SMFIP_NOBODY,
     "SMFIP_NOHDRS", SMFIP_NOHDRS,
     "SMFIP_NOEOH", SMFIP_NOEOH,
-#ifdef SMFIP_NOHREPL
-    "SMFIP_NOHREPL", SMFIP_NOHREPL,
-#endif
-#ifdef SMFIP_NOUNKNOWN
+    "SMFIP_NR_HDR", SMFIP_NR_HDR,
     "SMFIP_NOUNKNOWN", SMFIP_NOUNKNOWN,
-#endif
-#ifdef SMFIP_NODATA
     "SMFIP_NODATA", SMFIP_NODATA,
-#endif
+    /* Introduced with Sendmail 8.14. */
+    "SMFIP_SKIP", SMFIP_SKIP,
+    "SMFIP_RCPT_REJ", SMFIP_RCPT_REJ,
+    "SMFIP_NR_CONN", SMFIP_NR_CONN,
+    "SMFIP_NR_HELO", SMFIP_NR_HELO,
+    "SMFIP_NR_MAIL", SMFIP_NR_MAIL,
+    "SMFIP_NR_RCPT", SMFIP_NR_RCPT,
+    "SMFIP_NR_DATA", SMFIP_NR_DATA,
+    "SMFIP_NR_UNKN", SMFIP_NR_UNKN,
+    "SMFIP_NR_EOH", SMFIP_NR_EOH,
+    "SMFIP_NR_BODY", SMFIP_NR_BODY,
+    "SMFIP_HDR_LEADSPC", SMFIP_HDR_LEADSPC,
     0, 0,
 };
 
@@ -376,9 +456,11 @@ static NAME_MASK smfif_table[] = {
     "SMFIF_ADDRCPT", SMFIF_ADDRCPT,
     "SMFIF_DELRCPT", SMFIF_DELRCPT,
     "SMFIF_CHGHDRS", SMFIF_CHGHDRS,
-#ifdef SMFIF_QUARANTINE
     "SMFIF_QUARANTINE", SMFIF_QUARANTINE,
-#endif
+    /* Introduced with Sendmail 8.14. */
+    "SMFIF_CHGFROM", SMFIF_CHGFROM,
+    "SMFIF_ADDRCPT_PAR", SMFIF_ADDRCPT_PAR,
+    "SMFIF_SETSYMLIST", SMFIF_SETSYMLIST,
     0, 0,
 };
 
@@ -519,26 +601,30 @@ static int milter8_read_resp(MILTER8 *milter, int event, unsigned char *command,
     }
 }
 
+static int milter8_read_data(MILTER8 *milter, ssize_t *data_len,...);
+
 /* vmilter8_read_data - read command data */
 
-static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
+static int vmilter8_read_data(MILTER8 *milter, ssize_t *data_len, va_list ap)
 {
     const char *myname = "milter8_read_data";
     int     arg_type;
-    int     data_left;
     UINT32_TYPE net_long;
     UINT32_TYPE *host_long_ptr;
     VSTRING *buf;
     int     ch;
+    int     ret;
+    UINT32_TYPE mac_type;
+    char  **mac_value_ptr;
 
-    for (data_left = data_len; (arg_type = va_arg(ap, int)) > 0; /* void */ ) {
+    while ((arg_type = va_arg(ap, int)) > 0) {
        switch (arg_type) {
 
            /*
             * Host order long.
             */
        case MILTER8_DATA_HLONG:
-           if (data_left < UINT32_SIZE) {
+           if (*data_len < UINT32_SIZE) {
                msg_warn("milter %s: input packet too short for network long",
                         milter->m.name);
                return (milter8_comm_error(milter));
@@ -550,7 +636,7 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
                         milter->m.name);
                return (milter8_comm_error(milter));
            }
-           data_left -= UINT32_SIZE;
+           *data_len -= UINT32_SIZE;
            *host_long_ptr = ntohl(net_long);
            break;
 
@@ -558,27 +644,27 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
             * Raw on-the-wire format, without explicit null terminator.
             */
        case MILTER8_DATA_BUFFER:
-           if (data_left < 0) {
+           if (*data_len < 0) {
                msg_warn("milter %s: no data in input packet", milter->m.name);
                return (milter8_comm_error(milter));
            }
            buf = va_arg(ap, VSTRING *);
            VSTRING_RESET(buf);
-           VSTRING_SPACE(buf, data_left);
-           if (vstream_fread(milter->fp, (char *) STR(buf), data_left)
-               != data_left) {
+           VSTRING_SPACE(buf, *data_len);
+           if (vstream_fread(milter->fp, (char *) STR(buf), *data_len)
+               != *data_len) {
                msg_warn("milter %s: EOF while reading data: %m", milter->m.name);
                return (milter8_comm_error(milter));
            }
-           VSTRING_AT_OFFSET(buf, data_left);
-           data_left = 0;
+           VSTRING_AT_OFFSET(buf, *data_len);
+           *data_len = 0;
            break;
 
            /*
             * Pointer to null-terminated string.
             */
        case MILTER8_DATA_STRING:
-           if (data_left < 1) {
+           if (*data_len < 1) {
                msg_warn("milter %s: packet too short for string",
                         milter->m.name);
                return (milter8_comm_error(milter));
@@ -591,11 +677,11 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
                             myname, milter->m.name);
                    return (milter8_comm_error(milter));
                }
-               data_left -= 1;
+               *data_len -= 1;
                if (ch == 0)
                    break;
                VSTRING_ADDCH(buf, ch);
-               if (data_left <= 0) {
+               if (*data_len <= 0) {
                    msg_warn("%s: milter %s: missing string null termimator",
                             myname, milter->m.name);
                    return (milter8_comm_error(milter));
@@ -604,6 +690,34 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
            VSTRING_TERMINATE(buf);
            break;
 
+           /*
+            * Sequence of macro (state, names) without explicit terminator.
+            */
+       case MILTER8_DATA_MACROS:
+           if (*data_len <= 0)
+               break;
+           buf = vstring_alloc(100);
+           ret = 0;
+           while (*data_len > 0
+                  && (ret = milter8_read_data(milter, data_len,
+                                              MILTER8_DATA_HLONG, &mac_type,
+                                              MILTER8_DATA_STRING, buf,
+                                              MILTER8_DATA_END)) == 0) {
+               if (((unsigned) mac_type) > SMFIM_LAST) {
+                   msg_warn("milter %s: ignoring unknown macro type %u",
+                            milter->m.name, (unsigned) mac_type);
+               } else {
+                   mac_value_ptr = MILTER8_MACRO_PTR(milter->m.parent, mac_type);
+                   if (*mac_value_ptr != 0)
+                       myfree(*mac_value_ptr);
+                   *mac_value_ptr = mystrdup(STR(buf));
+               }
+           }
+           vstring_free(buf);
+           if (ret != 0)
+               return (ret);
+           break;
+
            /*
             * Error.
             */
@@ -616,19 +730,19 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t data_len, va_list ap)
      * Sanity checks. We may have excess data when the sender is confused. We
      * may have a negative count when we're confused ourselves.
      */
-    if (data_left > 0) {
-       msg_warn("%s: left-over data %ld bytes", myname, (long) data_left);
+    if (*data_len > 0) {
+       msg_warn("%s: left-over data %ld bytes", myname, (long) *data_len);
        return (milter8_comm_error(milter));
     }
-    if (data_left < 0)
+    if (*data_len < 0)
        msg_panic("%s: bad left-over data count %ld",
-                 myname, (long) data_left);
+                 myname, (long) *data_len);
     return (0);
 }
 
 /* milter8_read_data - read command data */
 
-static int milter8_read_data(MILTER8 *milter, ssize_t data_len,...)
+static int milter8_read_data(MILTER8 *milter, ssize_t *data_len,...)
 {
     va_list ap;
     int     ret;
@@ -883,10 +997,27 @@ static const char *milter8_event(MILTER8 *milter, int event,
        return (milter->def_reply);
     }
 
+    /*
+     * Skip further events of this type if the filter told us so.
+     */
+    if (milter->skip_event_type != 0) {
+       if (event == milter->skip_event_type) {
+           if (msg_verbose)
+               msg_info("skipping event %s after SMFIR_SKIP from milter %s",
+                    (smfic_name = str_name_code(smfic_table, event)) != 0 ?
+                        smfic_name : "(unknown MTA event)", milter->m.name);
+           return (milter->def_reply);
+       } else {
+           milter->skip_event_type = 0;
+       }
+    }
+
     /*
      * Send the macros for this event, even when we're not reporting the
      * event itself. This does not introduce a performance problem because
      * we're sending macros and event parameters in one VSTREAM transaction.
+     * 
+     * XXX Is this still necessary?
      */
     if (msg_verbose) {
        VSTRING *buf = vstring_alloc(100);
@@ -1118,7 +1249,6 @@ static const char *milter8_event(MILTER8 *milter, int event,
             * Decision: disconnect. This decision is final (i.e. Sendmail 8
             * changes receiver state).
             */
-#ifdef SMFIR_SHUTDOWN
        case SMFIR_SHUTDOWN:
            if (data_size != 0)
                break;
@@ -1127,7 +1257,6 @@ static const char *milter8_event(MILTER8 *milter, int event,
 #endif
            milter->state = MILTER8_STAT_REJECT_CON;
            MILTER8_EVENT_BREAK(milter8_def_reply(milter, "S"));
-#endif
 
            /*
             * Decision: "ddd d.d+.d+ text". This decision is final (i.e.
@@ -1140,7 +1269,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
             * by '%', and remove single (i.e. invalid) '%' characters.
             */
        case SMFIR_REPLYCODE:
-           if (milter8_read_data(milter, data_size,
+           if (milter8_read_data(milter, &data_size,
                                  MILTER8_DATA_BUFFER, milter->buf,
                                  MILTER8_DATA_END) != 0)
                MILTER8_EVENT_BREAK(milter->def_reply);
@@ -1178,15 +1307,22 @@ static const char *milter8_event(MILTER8 *milter, int event,
             * transition in the receiver state (reply, reject, tempfail,
             * accept, discard).
             */
-#ifdef SMFIR_QUARANTINE
        case SMFIR_QUARANTINE:
            /* XXX What to do with the "reason" text? */
-           if (milter8_read_data(milter, data_size,
+           if (milter8_read_data(milter, &data_size,
                                  MILTER8_DATA_BUFFER, milter->buf,
                                  MILTER8_DATA_END) != 0)
                MILTER8_EVENT_BREAK(milter->def_reply);
            MILTER8_EVENT_BREAK("H");
-#endif
+
+           /*
+            * Decision: skip further events of this type.
+            */
+       case SMFIR_SKIP:
+           if (data_size != 0)
+               break;
+           milter->skip_event_type = event;
+           MILTER8_EVENT_BREAK(milter->def_reply);
 
            /*
             * Modification request or error.
@@ -1195,13 +1331,14 @@ static const char *milter8_event(MILTER8 *milter, int event,
            if (event == SMFIC_BODYEOB) {
                switch (cmd) {
 
+#define MILTER8_HDR_SPACE(m) (((m)->ev_mask & SMFIP_HDR_LEADSPC) ? "" : " ")
+
                    /*
                     * Modification request: replace, insert or delete
                     * header. Index 1 means the first instance.
                     */
-#ifdef SMFIR_CHGHEADER
                case SMFIR_CHGHEADER:
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_HLONG, &index,
                                          MILTER8_DATA_STRING, milter->buf,
                                          MILTER8_DATA_STRING, milter->body,
@@ -1229,19 +1366,19 @@ static const char *milter8_event(MILTER8 *milter, int event,
                        edit_resp = parent->upd_header(parent->chg_context,
                                                       (ssize_t) index,
                                                       STR(milter->buf),
+                                                 MILTER8_HDR_SPACE(milter),
                                                       STR(milter->body));
                    else
                        edit_resp = parent->del_header(parent->chg_context,
                                                       (ssize_t) index,
                                                       STR(milter->buf));
                    continue;
-#endif
 
                    /*
                     * Modification request: append header.
                     */
                case SMFIR_ADDHEADER:
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_STRING, milter->buf,
                                          MILTER8_DATA_STRING, milter->body,
                                          MILTER8_DATA_END) != 0)
@@ -1251,6 +1388,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
                        continue;
                    edit_resp = parent->add_header(parent->chg_context,
                                                   STR(milter->buf),
+                                                  MILTER8_HDR_SPACE(milter),
                                                   STR(milter->body));
                    continue;
 
@@ -1260,9 +1398,8 @@ static const char *milter8_event(MILTER8 *milter, int event,
                     * indexing for consistency with header change
                     * operations.
                     */
-#ifdef SMFIR_INSHEADER
                case SMFIR_INSHEADER:
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_HLONG, &index,
                                          MILTER8_DATA_STRING, milter->buf,
                                          MILTER8_DATA_STRING, milter->body,
@@ -1280,15 +1417,15 @@ static const char *milter8_event(MILTER8 *milter, int event,
                    edit_resp = parent->ins_header(parent->chg_context,
                                                   (ssize_t) index + 1,
                                                   STR(milter->buf),
+                                                  MILTER8_HDR_SPACE(milter),
                                                   STR(milter->body));
                    continue;
-#endif
 
                    /*
                     * Modification request: append recipient.
                     */
                case SMFIR_ADDRCPT:
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_STRING, milter->buf,
                                          MILTER8_DATA_END) != 0)
                        MILTER8_EVENT_BREAK(milter->def_reply);
@@ -1303,7 +1440,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
                     * Modification request: delete (expansion of) recipient.
                     */
                case SMFIR_DELRCPT:
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_STRING, milter->buf,
                                          MILTER8_DATA_END) != 0)
                        MILTER8_EVENT_BREAK(milter->def_reply);
@@ -1326,7 +1463,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
                        milter8_conf_error(milter);
                        MILTER8_EVENT_BREAK(milter->def_reply);
                    }
-                   if (milter8_read_data(milter, data_size,
+                   if (milter8_read_data(milter, &data_size,
                                          MILTER8_DATA_BUFFER, milter->body,
                                          MILTER8_DATA_END) != 0)
                        MILTER8_EVENT_BREAK(milter->def_reply);
@@ -1413,9 +1550,12 @@ static void milter8_connect(MILTER8 *milter)
     const UINT32_TYPE my_actions = (SMFIF_ADDHDRS | SMFIF_ADDRCPT
                                    | SMFIF_DELRCPT | SMFIF_CHGHDRS
                                    | SMFIF_CHGBODY
-#ifdef SMFIF_QUARANTINE
                                    | SMFIF_QUARANTINE
+#if 0
+                                   | SMFIF_CHGFROM
+                                   | SMFIF_ADDRCPT_PAR
 #endif
+                                   | SMFIF_SETSYMLIST
     );
 
     UINT32_TYPE my_version = 0;
@@ -1472,13 +1612,9 @@ static void milter8_connect(MILTER8 *milter)
     }
 
     /*
-     * Don't send events that aren't defined for my protocol version. This is
-     * somewhat tricky: unlike the other SMFIP_mumble bits, the SMFIP_NOHREPL
-     * bit specifies something that the milter application won't send. We
-     * must not inadvertently turn this bit on, because the MTA would get out
-     * of sync with the application.
+     * Don't send events that aren't defined for my protocol version.
      */
-    milter->np_mask = ~(my_events | SMFIP_NOHREPL);
+    milter->np_mask = (SMFIP_NOSEND_MASK & ~my_events);
     if (msg_verbose)
        msg_info("%s: non-protocol events for protocol version %d: %s",
                 myname, my_version,
@@ -1565,10 +1701,11 @@ static void milter8_connect(MILTER8 *milter)
        msg_warn("milter %s: unexpected reply \"%c\" in initial handshake",
                 milter->m.name, cmd);
        (void) milter8_comm_error(milter);
-    } else if (milter8_read_data(milter, data_len,
+    } else if (milter8_read_data(milter, &data_len,
                                 MILTER8_DATA_HLONG, &milter->version,
                                 MILTER8_DATA_HLONG, &milter->rq_mask,
                                 MILTER8_DATA_HLONG, &milter->ev_mask,
+                                MILTER8_DATA_MACROS,
                                 MILTER8_DATA_END) != 0) {
        msg_warn("milter %s: read error in initial handshake", milter->m.name);
        /* milter8_read_data() called milter8_comm_error() */
@@ -1604,6 +1741,7 @@ static void milter8_connect(MILTER8 *milter)
        }
        milter->state = MILTER8_STAT_READY;
        milter8_def_reply(milter, 0);
+       milter->skip_event_type = 0;
     }
 }
 
@@ -1619,6 +1757,7 @@ static const char *milter8_conn_event(MILTER *m,
     const char *myname = "milter8_conn_event";
     MILTER8 *milter = (MILTER8 *) m;
     int     port;
+    int     skip_reply;
 
     /*
      * XXX Sendmail 8 libmilter closes the MTA-to-filter socket when it finds
@@ -1650,10 +1789,11 @@ static const char *milter8_conn_event(MILTER *m,
            port = 0;
        }
        milter->state = MILTER8_STAT_ENVELOPE;
+       skip_reply = ((milter->ev_mask & SMFIP_NR_CONN) != 0);
        switch (addr_family) {
        case AF_INET:
            return (milter8_event(milter, SMFIC_CONNECT, SMFIP_NOCONNECT,
-                                 DONT_SKIP_REPLY, macros,
+                                 skip_reply, macros,
                                  MILTER8_DATA_STRING, client_name,
                                  MILTER8_DATA_OCTET, SMFIA_INET,
                                  MILTER8_DATA_NSHORT, htons(port),
@@ -1662,7 +1802,7 @@ static const char *milter8_conn_event(MILTER *m,
 #ifdef HAS_IPV6
        case AF_INET6:
            return (milter8_event(milter, SMFIC_CONNECT, SMFIP_NOCONNECT,
-                                 DONT_SKIP_REPLY, macros,
+                                 skip_reply, macros,
                                  MILTER8_DATA_STRING, client_name,
                                  MILTER8_DATA_OCTET, SMFIA_INET6,
                                  MILTER8_DATA_NSHORT, htons(port),
@@ -1671,7 +1811,7 @@ static const char *milter8_conn_event(MILTER *m,
 #endif
        case AF_UNIX:
            return (milter8_event(milter, SMFIC_CONNECT, SMFIP_NOCONNECT,
-                                 DONT_SKIP_REPLY, macros,
+                                 skip_reply, macros,
                                  MILTER8_DATA_STRING, client_name,
                                  MILTER8_DATA_OCTET, SMFIA_UNIX,
                                  MILTER8_DATA_NSHORT, htons(0),
@@ -1679,7 +1819,7 @@ static const char *milter8_conn_event(MILTER *m,
                                  MILTER8_DATA_END));
        default:
            return (milter8_event(milter, SMFIC_CONNECT, SMFIP_NOCONNECT,
-                                 DONT_SKIP_REPLY, macros,
+                                 skip_reply, macros,
                                  MILTER8_DATA_STRING, client_name,
                                  MILTER8_DATA_OCTET, SMFIA_UNKNOWN,
                                  MILTER8_DATA_END));
@@ -1698,6 +1838,7 @@ static const char *milter8_helo_event(MILTER *m, const char *helo_name,
 {
     const char *myname = "milter8_helo_event";
     MILTER8 *milter = (MILTER8 *) m;
+    int     skip_reply;
 
     /*
      * Report the event.
@@ -1715,8 +1856,9 @@ static const char *milter8_helo_event(MILTER *m, const char *helo_name,
        if (msg_verbose)
            msg_info("%s: milter %s: helo %s",
                     myname, milter->m.name, helo_name);
+       skip_reply = ((milter->ev_mask & SMFIP_NR_HELO) != 0);
        return (milter8_event(milter, SMFIC_HELO, SMFIP_NOHELO,
-                             DONT_SKIP_REPLY, macros,
+                             skip_reply, macros,
                              MILTER8_DATA_STRING, helo_name,
                              MILTER8_DATA_END));
     default:
@@ -1733,6 +1875,7 @@ static const char *milter8_mail_event(MILTER *m, const char **argv,
     const char *myname = "milter8_mail_event";
     MILTER8 *milter = (MILTER8 *) m;
     const char **cpp;
+    int     skip_reply;
 
     /*
      * Report the event.
@@ -1754,8 +1897,9 @@ static const char *milter8_mail_event(MILTER *m, const char **argv,
                     myname, milter->m.name, STR(buf));
            vstring_free(buf);
        }
+       skip_reply = ((milter->ev_mask & SMFIP_NR_MAIL) != 0);
        return (milter8_event(milter, SMFIC_MAIL, SMFIP_NOMAIL,
-                             DONT_SKIP_REPLY, macros,
+                             skip_reply, macros,
                              MILTER8_DATA_ARGV, argv,
                              MILTER8_DATA_END));
     default:
@@ -1772,6 +1916,7 @@ static const char *milter8_rcpt_event(MILTER *m, const char **argv,
     const char *myname = "milter8_rcpt_event";
     MILTER8 *milter = (MILTER8 *) m;
     const char **cpp;
+    int     skip_reply;
 
     /*
      * Report the event.
@@ -1794,8 +1939,9 @@ static const char *milter8_rcpt_event(MILTER *m, const char **argv,
                     myname, milter->m.name, STR(buf));
            vstring_free(buf);
        }
+       skip_reply = ((milter->ev_mask & SMFIP_NR_RCPT) != 0);
        return (milter8_event(milter, SMFIC_RCPT, SMFIP_NORCPT,
-                             DONT_SKIP_REPLY, macros,
+                             skip_reply, macros,
                              MILTER8_DATA_ARGV, argv,
                              MILTER8_DATA_END));
     default:
@@ -1806,12 +1952,11 @@ static const char *milter8_rcpt_event(MILTER *m, const char **argv,
 
 /* milter8_data_event - report DATA command to Sendmail 8 milter */
 
-#ifdef SMFIC_DATA
-
 static const char *milter8_data_event(MILTER *m, ARGV *macros)
 {
     const char *myname = "milter8_data_event";
     MILTER8 *milter = (MILTER8 *) m;
+    int     skip_reply;
 
     /*
      * Report the event.
@@ -1827,8 +1972,9 @@ static const char *milter8_data_event(MILTER *m, ARGV *macros)
     case MILTER8_STAT_ENVELOPE:
        if (msg_verbose)
            msg_info("%s: milter %s: data command", myname, milter->m.name);
+       skip_reply = ((milter->ev_mask & SMFIP_NR_DATA) != 0);
        return (milter8_event(milter, SMFIC_DATA, SMFIP_NODATA,
-                             DONT_SKIP_REPLY, macros,
+                             skip_reply, macros,
                              MILTER8_DATA_END));
     default:
        msg_panic("%s: milter %s: bad state %d",
@@ -1836,19 +1982,14 @@ static const char *milter8_data_event(MILTER *m, ARGV *macros)
     }
 }
 
-#else
-#define milter8_data_event     0
-#endif
-
 /* milter8_unknown_event - report unknown SMTP command to Sendmail 8 milter */
 
-#ifdef SMFIC_UNKNOWN
-
 static const char *milter8_unknown_event(MILTER *m, const char *command,
                                                 ARGV *macros)
 {
     const char *myname = "milter8_unknown_event";
     MILTER8 *milter = (MILTER8 *) m;
+    int     skip_reply;
 
     /*
      * Report the event.
@@ -1866,8 +2007,9 @@ static const char *milter8_unknown_event(MILTER *m, const char *command,
            msg_info("%s: milter %s: unknown command: %s",
                     myname, milter->m.name, command);
        /* XXX Sendmail doesn't send macros (checked with 8.6.13). */
+       skip_reply = ((milter->ev_mask & SMFIP_NR_UNKN) != 0);
        return (milter8_event(milter, SMFIC_UNKNOWN, SMFIP_NOUNKNOWN,
-                             DONT_SKIP_REPLY, macros,
+                             skip_reply, macros,
                              MILTER8_DATA_STRING, command,
                              MILTER8_DATA_END));
     default:
@@ -1876,10 +2018,6 @@ static const char *milter8_unknown_event(MILTER *m, const char *command,
     }
 }
 
-#else
-#define milter8_unknown_event  0
-#endif
-
 /* milter8_other_event - reply for other event */
 
 static const char *milter8_other_event(MILTER *m)
@@ -1982,7 +2120,8 @@ static void milter8_disc_event(MILTER *m)
   */
 typedef struct {
     MILTER8 *milter;                   /* milter client */
-    ARGV   *macros;                    /* end-of-body macros */
+    ARGV   *eoh_macros;                        /* end-of-header macros */
+    ARGV   *eod_macros;                        /* end-of-body macros */
     int     first_header;              /* first header */
     int     first_body;                        /* first body line */
     const char *resp;                  /* milter application response */
@@ -2049,17 +2188,13 @@ static void milter8_header(void *ptr, int unused_header_class,
     if (*cp != ':')
        msg_panic("%s: header label not followed by ':'", myname);
     *cp++ = 0;
-    /* XXX Sendmail 8.13.6 eats one space (not tab) after colon. */
-    if (*cp == ' ')
+    /* XXX Sendmail by default eats one space (not tab) after the colon. */
+    if ((milter->ev_mask & SMFIP_HDR_LEADSPC) == 0 && *cp == ' ')
        cp++;
-#ifdef SMFIP_NOHREPL
     skip_reply = ((milter->ev_mask & SMFIP_NOHREPL) != 0);
-#else
-    skip_reply = DONT_SKIP_REPLY;
-#endif
     msg_ctx->resp =
        milter8_event(milter, SMFIC_HEADER, SMFIP_NOHDRS,
-                     skip_reply, msg_ctx->macros,
+                     skip_reply, msg_ctx->eoh_macros,
                      MILTER8_DATA_STRING, STR(buf),
                      MILTER8_DATA_STRING, cp,
                      MILTER8_DATA_END);
@@ -2072,14 +2207,16 @@ static void milter8_eoh(void *ptr)
     const char *myname = "milter8_eoh";
     MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr;
     MILTER8 *milter = msg_ctx->milter;
+    int     skip_reply;
 
     if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
        return;
     if (msg_verbose)
        msg_info("%s: eoh milter %s", myname, milter->m.name);
+    skip_reply = ((milter->ev_mask & SMFIP_NR_EOH) != 0);
     msg_ctx->resp =
        milter8_event(milter, SMFIC_EOH, SMFIP_NOEOH,
-                     DONT_SKIP_REPLY, msg_ctx->macros,
+                     skip_reply, msg_ctx->eoh_macros,
                      MILTER8_DATA_END);
 }
 
@@ -2096,6 +2233,7 @@ static void milter8_body(void *ptr, int rec_type,
     const char *bp = buf;
     ssize_t space;
     ssize_t count;
+    int     skip_reply;
 
     if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
        return;
@@ -2123,6 +2261,7 @@ static void milter8_body(void *ptr, int rec_type,
      */
     if (msg_verbose > 1)
        msg_info("%s: body milter %s: %.100s", myname, milter->m.name, buf);
+    skip_reply = ((milter->ev_mask & SMFIP_NR_BODY) != 0);
     /* To append \r\n, simply redirect input to another buffer. */
     if (rec_type == REC_TYPE_NORM && todo == 0) {
        bp = "\r\n";
@@ -2143,7 +2282,7 @@ static void milter8_body(void *ptr, int rec_type,
        if (LEN(milter->body) == MILTER_CHUNK_SIZE) {
            msg_ctx->resp =
                milter8_event(milter, SMFIC_BODY, SMFIP_NOBODY,
-                             DONT_SKIP_REPLY, msg_ctx->macros,
+                             skip_reply, msg_ctx->eod_macros,
                              MILTER8_DATA_BUFFER, milter->body,
                              MILTER8_DATA_END);
            if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
@@ -2166,6 +2305,7 @@ static void milter8_eob(void *ptr)
     const char *myname = "milter8_eob";
     MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr;
     MILTER8 *milter = msg_ctx->milter;
+    int     skip_reply;
 
     if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
        return;
@@ -2184,9 +2324,10 @@ static void milter8_eob(void *ptr)
      * have different macro lists.
      */
     if (LEN(milter->body) > 0) {
+       skip_reply = ((milter->ev_mask & SMFIP_NR_BODY) != 0);
        msg_ctx->resp =
            milter8_event(milter, SMFIC_BODY, SMFIP_NOBODY,
-                         DONT_SKIP_REPLY, msg_ctx->macros,
+                         skip_reply, msg_ctx->eod_macros,
                          MILTER8_DATA_BUFFER, milter->body,
                          MILTER8_DATA_END);
        if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
@@ -2194,7 +2335,7 @@ static void milter8_eob(void *ptr)
     }
     msg_ctx->resp =
        milter8_event(msg_ctx->milter, SMFIC_BODYEOB, 0,
-                     DONT_SKIP_REPLY, msg_ctx->macros,
+                     DONT_SKIP_REPLY, msg_ctx->eod_macros,
                      MILTER8_DATA_END);
 }
 
@@ -2202,7 +2343,8 @@ static void milter8_eob(void *ptr)
 
 static const char *milter8_message(MILTER *m, VSTREAM *qfile,
                                           off_t data_offset,
-                                          ARGV *macros)
+                                          ARGV *eoh_macros,
+                                          ARGV *eod_macros)
 {
     const char *myname = "milter8_message";
     MILTER8 *milter = (MILTER8 *) m;
@@ -2229,7 +2371,8 @@ static const char *milter8_message(MILTER *m, VSTREAM *qfile,
            return ("450 4.3.0 Queue file write error");
        }
        msg_ctx.milter = milter;
-       msg_ctx.macros = macros;
+       msg_ctx.eoh_macros = eoh_macros;
+       msg_ctx.eod_macros = eod_macros;
        msg_ctx.first_header = 1;
        msg_ctx.first_body = 1;
        msg_ctx.resp = 0;
@@ -2504,6 +2647,7 @@ static MILTER8 *milter8_alloc(const char *name, int conn_timeout,
     milter->protocol = (protocol ? mystrdup(protocol) : 0);
     milter->def_action = mystrdup(def_action);
     milter->def_reply = 0;
+    milter->skip_event_type = 0;
 
     return (milter);
 }
index c645b316ed44859999b711fa4e7f3a4176eb110c..c13f6be67e7c68836d2f4a077c0fdb47bb08218c 100644 (file)
@@ -16,9 +16,9 @@
 /*     to maintain compatibility between successive versions.
 /*
 /*     Arguments (multiple alternatives are separated by "\fB|\fR"):
-/* .IP "\fB-a accept|tempfail|reject|discard|\fIddd x.y.z text\fR"
-/*     Specifies a non-default reply. The default is to continue
-/*     (i.e. \fBtempfail\fR).
+/* .IP "\fB-a accept|tempfail|reject|discard|skip|\fIddd x.y.z text\fR"
+/*     Specifies a non-default reply for the MTA command specified
+/*     with \fB-a\fR. The default is \fBtempfail\fR.
 /* .IP "\fB-d\fI level\fR"
 /*     Enable libmilter debugging at the specified level.
 /* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
 /*     The default protocol stage is \fBconnect\fR.
 /* .IP "\fB-C\fI count\fR"
 /*     Terminate after \fIcount\fR connections.
-/* .IP "\fB-i \"\fIindex header-label header-value\"\fR"
+/* .IP "\fB-i \fI'index header-label header-value'\fR"
 /*     Insert header at specified position.
+/* .IP "\fB-m connect|helo|mail|rcpt|data|eoh|eom\fR"
+/*     The protocol stage that receives the list of macros specified
+/*     with \fB-M\fR.  The default protocol stage is \fBconnect\fR.
+/* .IP "\fB-M \fIset_macro_list\fR"
+/*     A non-default list of macros that the MTA should send at
+/*     the protocol stage specified with \fB-m\fR.
+/* .IP "\fB-n connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
+/*     The event that the MTA should not send.
+/* .IP "\fB-N connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
+/*     The event for which the filter will not reply.
 /* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR"
 /*     The mail filter listen endpoint.
-/* .IP "\fB-r "index header-label header-value"
+/* .IP "\fB-r \fI'index header-label header-value'\fR"
 /*     Replace the message header at the specified position.
 /* .IP "\fB-R pathname
 /*     Replace the message body by the content of the specified file.
@@ -95,18 +105,18 @@ static struct command_map command_map[] = {
     "helo", &test_helo_reply,
     "mail", &test_mail_reply,
     "rcpt", &test_rcpt_reply,
-#if SMFI_VERSION > 3
-    "data", &test_data_reply,
-#endif
     "header", &test_header_reply,
     "eoh", &test_eoh_reply,
     "body", &test_body_reply,
     "eom", &test_eom_reply,
+    "abort", &test_abort_reply,
+    "close", &test_close_reply,
 #if SMFI_VERSION > 2
     "unknown", &test_unknown_reply,
 #endif
-    "close", &test_close_reply,
-    "abort", &test_abort_reply,
+#if SMFI_VERSION > 3
+    "data", &test_data_reply,
+#endif
     0, 0,
 };
 
@@ -258,8 +268,8 @@ static sfsistat test_eom(SMFICTX *ctx)
            printf("replace body with content of %s\n", body_file);
            for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
                len = strcspn(buf, "\n");
-               buf[len+0] = '\r';
-               buf[len+1] = '\n';
+               buf[len + 0] = '\r';
+               buf[len + 1] = '\n';
                if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
                    fprintf(stderr, "body replace failure\n");
                    exit(1);
@@ -312,14 +322,19 @@ static sfsistat test_data(SMFICTX *ctx)
 
 #if SMFI_VERSION > 2
 
-static sfsistat test_unknown(SMFICTX *ctx)
+static sfsistat test_unknown(SMFICTX *ctx, const char *what)
 {
-    printf("test_unknown\n");
+    printf("test_unknown %s\n", what);
     return (test_reply(ctx, test_unknown_reply));
 }
 
 #endif
 
+static sfsistat test_negotiate(SMFICTX *, unsigned long, unsigned long,
+                                      unsigned long, unsigned long,
+                                      unsigned long *, unsigned long *,
+                                      unsigned long *, unsigned long *);
+
 static struct smfiDesc smfilter =
 {
     "test-milter",
@@ -341,8 +356,79 @@ static struct smfiDesc smfilter =
 #if SMFI_VERSION > 3
     test_data,
 #endif
+#if SMFI_VERSION > 5
+    test_negotiate,
+#endif
 };
 
+#if SMFI_VERSION > 5
+
+static const char *macro_states[] = {
+    "connect",                         /* SMFIM_CONNECT */
+    "helo",                            /* SMFIM_HELO */
+    "mail",                            /* SMFIM_ENVFROM */
+    "rcpt",                            /* SMFIM_ENVRCPT */
+    "data",                            /* SMFIM_DATA */
+    "eom",                             /* SMFIM_EOM < SMFIM_EOH */
+    "eoh",                             /* SMFIM_EOH > SMFIM_EOM */
+    0,
+};
+
+static int set_macro_state;
+static char *set_macro_list;
+
+typedef sfsistat (*FILTER_ACTION) ();
+
+struct noproto_map {
+    const char *name;
+    int     send_mask;
+    int     reply_mask;
+    int    *reply;
+    FILTER_ACTION *action;
+};
+
+static struct noproto_map noproto_map[] = {
+    "connect", SMFIP_NOCONNECT, SMFIP_NR_CONN, &test_connect_reply, &smfilter.xxfi_connect,
+    "helo", SMFIP_NOHELO, SMFIP_NR_HELO, &test_helo_reply, &smfilter.xxfi_helo,
+    "mail", SMFIP_NOMAIL, SMFIP_NR_MAIL, &test_mail_reply, &smfilter.xxfi_envfrom,
+    "rcpt", SMFIP_NORCPT, SMFIP_NR_RCPT, &test_rcpt_reply, &smfilter.xxfi_envrcpt,
+    "data", SMFIP_NODATA, SMFIP_NR_DATA, &test_data_reply, &smfilter.xxfi_data,
+    "header", SMFIP_NOHDRS, SMFIP_NR_HDR, &test_header_reply, &smfilter.xxfi_header,
+    "eoh", SMFIP_NOEOH, SMFIP_NR_EOH, &test_eoh_reply, &smfilter.xxfi_eoh,
+    "body", SMFIP_NOBODY, SMFIP_NR_BODY, &test_body_reply, &smfilter.xxfi_body,
+    "unknown", SMFIP_NOUNKNOWN, SMFIP_NR_UNKN, &test_connect_reply, &smfilter.xxfi_unknown,
+    0,
+};
+
+static int nosend_mask;
+static int noreply_mask;
+
+static sfsistat test_negotiate(SMFICTX *ctx,
+                                      unsigned long f0,
+                                      unsigned long f1,
+                                      unsigned long f2,
+                                      unsigned long f3,
+                                      unsigned long *pf0,
+                                      unsigned long *pf1,
+                                      unsigned long *pf2,
+                                      unsigned long *pf3)
+{
+    if (set_macro_list) {
+       if (verbose)
+           printf("set symbol list %s to \"%s\"\n",
+                  macro_states[set_macro_state], set_macro_list);
+       smfi_setsymlist(ctx, set_macro_state, set_macro_list);
+    }
+    if (verbose)
+       printf("negotiate f0=%lx *pf0 = %lx f1=%lx *pf1=%lx nosend=%lx noreply=%lx\n",
+              f0, *pf0, f1, *pf1, (long) nosend_mask, (long) noreply_mask);
+    *pf0 = f0;
+    *pf1 = f1 & (nosend_mask | noreply_mask);
+    return (SMFIS_CONTINUE);
+}
+
+#endif
+
 static void parse_hdr_info(const char *optarg, int *idx,
                                   char **hdr, char **value)
 {
@@ -366,8 +452,13 @@ int     main(int argc, char **argv)
     struct command_map *cp;
     int     ch;
     int     code;
+    const char **cpp;
+    char   *set_macro_state_arg = 0;
+    char   *nosend = 0;
+    char   *noreply = 0;
+    struct noproto_map *np;
 
-    while ((ch = getopt(argc, argv, "a:c:C:d:i:p:r:R:v")) > 0) {
+    while ((ch = getopt(argc, argv, "a:c:C:d:i:m:M:n:N:p:r:R:v")) > 0) {
        switch (ch) {
        case 'a':
            action = optarg;
@@ -391,6 +482,50 @@ int     main(int argc, char **argv)
 #else
            fprintf(stderr, "no libmilter support to insert header\n");
            exit(1);
+#endif
+           break;
+       case 'm':
+#if SMFI_VERSION > 5
+           if (set_macro_state_arg) {
+               fprintf(stderr, "too many -m options\n");
+               exit(1);
+           }
+           set_macro_state_arg = optarg;
+#else
+           fprintf(stderr, "no libmilter support to specify macro list\n");
+#endif
+           break;
+       case 'M':
+#if SMFI_VERSION > 5
+           if (set_macro_list) {
+               fprintf(stderr, "too many -M options\n");
+               exit(1);
+           }
+           set_macro_list = optarg;
+#else
+           fprintf(stderr, "no libmilter support to specify macro list\n");
+#endif
+           break;
+       case 'n':
+#if SMFI_VERSION > 5
+           if (nosend) {
+               fprintf(stderr, "too many -n options\n");
+               exit(1);
+           }
+           nosend = optarg;
+#else
+           fprintf(stderr, "no libmilter support for negotiate callback\n");
+#endif
+           break;
+       case 'N':
+#if SMFI_VERSION > 5
+           if (noreply) {
+               fprintf(stderr, "too many -n options\n");
+               exit(1);
+           }
+           noreply = optarg;
+#else
+           fprintf(stderr, "no libmilter support for negotiate callback\n");
 #endif
            break;
        case 'p':
@@ -432,6 +567,10 @@ int     main(int argc, char **argv)
                    "\t[-a action]              non-default action\n"
                    "\t[-c command]             non-default action trigger\n"
                    "\t[-i 'index label value'] insert header\n"
+                   "\t[-m macro_state]         non-default macro state\n"
+                   "\t[-M macro_list]          non-default macro list\n"
+                   "\t[-n events]              don't receive these events\n"
+                 "\t[-N events]                don't reply to these events\n"
                    "\t-p port                  milter application\n"
                    "\t[-r 'index label value'] replace header\n"
                    "\t[-C conn_count]          when to exit\n",
@@ -440,10 +579,6 @@ int     main(int argc, char **argv)
            exit(1);
        }
     }
-    if (smfi_register(smfilter) == MI_FAILURE) {
-       fprintf(stderr, "smfi_register failed\n");
-       exit(1);
-    }
     if (command) {
        for (cp = command_map; /* see below */ ; cp++) {
            if (cp->name == 0) {
@@ -465,6 +600,10 @@ int     main(int argc, char **argv)
            cp->reply[0] = SMFIS_ACCEPT;
        } else if (strcmp(action, "discard") == 0) {
            cp->reply[0] = SMFIS_DISCARD;
+#ifdef SMFIS_SKIP
+       } else if (strcmp(action, "skip") == 0) {
+           cp->reply[0] = SMFIS_SKIP;
+#endif
        } else if ((code = atoi(action)) >= 400
                   && code <= 599
                   && action[3] == ' ') {
@@ -498,5 +637,46 @@ int     main(int argc, char **argv)
                       reply_message ? reply_message : "(null)");
        }
     }
+#if SMFI_VERSION > 5
+    if (set_macro_state_arg) {
+       for (cpp = macro_states; /* see below */ ; cpp++) {
+           if (*cpp == 0) {
+               fprintf(stderr, "bad -m argument: %s\n", set_macro_state_arg);
+               exit(1);
+           }
+           if (strcmp(set_macro_state_arg, *cpp) == 0)
+               break;
+       }
+       set_macro_state = cpp - macro_states;
+    }
+    if (nosend) {
+       for (np = noproto_map; /* see below */ ; np++) {
+           if (np->name == 0) {
+               fprintf(stderr, "bad -n argument: %s\n", nosend);
+               exit(1);
+           }
+           if (strcmp(nosend, np->name) == 0)
+               break;
+       }
+       nosend_mask = np->send_mask;
+       np->action[0] = 0;
+    }
+    if (noreply) {
+       for (np = noproto_map; /* see below */ ; np++) {
+           if (np->name == 0) {
+               fprintf(stderr, "bad -N argument: %s\n", noreply);
+               exit(1);
+           }
+           if (strcmp(noreply, np->name) == 0)
+               break;
+       }
+       noreply_mask = np->reply_mask;
+       *np->reply = SMFIS_NOREPLY;
+    }
+#endif
+    if (smfi_register(smfilter) == MI_FAILURE) {
+       fprintf(stderr, "smfi_register failed\n");
+       exit(1);
+    }
     return (smfi_main());
 }
index 24dd01d0cfe42f5c58c0cb4012754aa66f913124..48d2e3eba8f4dc0161802aaa92183afbfe25e6bb 100644 (file)
@@ -394,8 +394,15 @@ int     smtp_helo(SMTP_STATE *state)
        where = "performing the EHLO handshake";
        if (session->features & SMTP_FEATURE_ESMTP) {
            smtp_chat_cmd(session, "EHLO %s", var_smtp_helo_name);
-           if ((resp = smtp_chat_resp(session))->code / 100 != 2)
-               session->features &= ~SMTP_FEATURE_ESMTP;
+           if ((resp = smtp_chat_resp(session))->code / 100 != 2) {
+               if (resp->code == 421)
+                   return (smtp_site_fail(state, session->host, resp,
+                                       "host %s refused to talk to me: %s",
+                                          session->namaddr,
+                                          translit(resp->str, "\n", " ")));
+               else
+                   session->features &= ~SMTP_FEATURE_ESMTP;
+           }
        }
        if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
            where = "performing the HELO handshake";
index 919af0ac93700f6c9ee9f47fec1ac258ad8bc487..16e550b46de6627bdf441a5fa501541dbb23d4fb 100644 (file)
 /* .IP "\fBmilter_unknown_command_macros (see postconf -n output)\fR"
 /*     The macros that are sent to version 3 or higher Milter (mail
 /*     filter) applications after an unknown SMTP command.
+/* .IP "\fBmilter_end_of_header_macros (see postconf -n output)\fR"
+/*     The macros that are sent to Milter (mail filter) applications
+/*     after the message header.
 /* .IP "\fBmilter_end_of_data_macros (see postconf -n output)\fR"
 /*     The macros that are sent to Milter (mail filter) applications
 /*     after the message end-of-data.
@@ -1127,6 +1130,7 @@ char   *var_milt_helo_macros;
 char   *var_milt_mail_macros;
 char   *var_milt_rcpt_macros;
 char   *var_milt_data_macros;
+char   *var_milt_eoh_macros;
 char   *var_milt_eod_macros;
 char   *var_milt_unk_macros;
 bool    var_smtpd_client_port_log;
@@ -4535,6 +4539,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
                                          var_milt_mail_macros,
                                          var_milt_rcpt_macros,
                                          var_milt_data_macros,
+                                         var_milt_eoh_macros,
                                          var_milt_eod_macros,
                                          var_milt_unk_macros);
        else
@@ -4724,6 +4729,7 @@ int     main(int argc, char **argv)
        VAR_MILT_MAIL_MACROS, DEF_MILT_MAIL_MACROS, &var_milt_mail_macros, 0, 0,
        VAR_MILT_RCPT_MACROS, DEF_MILT_RCPT_MACROS, &var_milt_rcpt_macros, 0, 0,
        VAR_MILT_DATA_MACROS, DEF_MILT_DATA_MACROS, &var_milt_data_macros, 0, 0,
+       VAR_MILT_EOH_MACROS, DEF_MILT_EOH_MACROS, &var_milt_eoh_macros, 0, 0,
        VAR_MILT_EOD_MACROS, DEF_MILT_EOD_MACROS, &var_milt_eod_macros, 0, 0,
        VAR_MILT_UNK_MACROS, DEF_MILT_UNK_MACROS, &var_milt_unk_macros, 0, 0,
        VAR_MILT_PROTOCOL, DEF_MILT_PROTOCOL, &var_milt_protocol, 1, 0,
index 4b5842b23019a8ff529a4c253ed942e7da1d4305..8ce3487037400f47c8bb6faf88907ed0f361cc65 100644 (file)
 /*     DATA, ., 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-Q \fIcommand,command,...\fR"
+/*     Disconnect after sending a 431 reply after receiving one
+/*     of the specified commands.
+/* .sp
+/*     Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/*     DATA, ., 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-r \fIcommand,command,...\fR"
 /*     Reject the specified commands with a soft (4xx) error code.
 /*     This option implies \fB-p\fR.
@@ -908,6 +916,7 @@ typedef struct SINK_COMMAND {
 #define FLAG_HARD_ERR  (1<<2)          /* report hard error */
 #define FLAG_SOFT_ERR  (1<<3)          /* report soft error */
 #define FLAG_DISCONNECT        (1<<4)          /* disconnect */
+#define FLAG_CLOSE     (1<<5)          /* say goodbye and disconnect */
 
 static SINK_COMMAND command_table[] = {
     "connect", conn_response, hard_err_resp, soft_err_resp, 0, 0, 0,
@@ -1021,6 +1030,10 @@ static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp,
        syslog(LOG_INFO, "%s %.100s", command, args);
     if (cmdp->flags & FLAG_DISCONNECT)
        return (-1);
+    if (cmdp->flags & FLAG_CLOSE) {
+       smtp_printf(state->stream, "421 4.0.0 Server closing connection");
+       return (-1);
+    }
     if (cmdp->flags & FLAG_HARD_ERR) {
        cmdp->hard_response(state);
        return (0);
@@ -1376,7 +1389,7 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "468aA:cCd:D:eEf:Fh:Ln:m:pPq:r:R:s:S:t:u:vw:W:")) > 0) {
+    while ((ch = GETOPT(argc, argv, "468aA:cCd:D:eEf:Fh:Ln:m:pPq:Q:r:R:s:S:t:u:vw:W:")) > 0) {
        switch (ch) {
        case '4':
            protocols = INET_PROTO_NAME_IPV4;
@@ -1445,6 +1458,9 @@ int     main(int argc, char **argv)
        case 'q':
            set_cmds_flags(optarg, FLAG_DISCONNECT);
            break;
+       case 'Q':
+           set_cmds_flags(optarg, FLAG_CLOSE);
+           break;
        case 'r':
            set_cmds_flags(optarg, FLAG_SOFT_ERR);
            disable_pipelining = 1;