]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.2-20040422
authorWietse Venema <wietse@porcupine.org>
Thu, 22 Apr 2004 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:29:36 +0000 (06:29 +0000)
33 files changed:
postfix/AAAREADME
postfix/README_FILES/PACKAGE_README
postfix/README_FILES/QSHAPE_README
postfix/README_FILES/RESTRICTION_CLASS_README
postfix/README_FILES/SMTPD_ACCESS_README
postfix/RELEASE_NOTES-2.1 [moved from postfix/RELEASE_NOTES-2.2 with 97% similarity]
postfix/TODO-BEFORE-RELEASE [deleted file]
postfix/conf/postfix-files
postfix/conf/transport
postfix/html/Makefile.in
postfix/html/PACKAGE_README.html
postfix/html/QSHAPE_README.html
postfix/html/RESTRICTION_CLASS_README.html
postfix/html/SMTPD_ACCESS_README.html
postfix/html/STANDARD_CONFIGURATION_README.html
postfix/html/postconf.1.html
postfix/html/postconf.5.html
postfix/html/qshape.1.html [new file with mode: 0644]
postfix/html/transport.5.html
postfix/man/junk [new file with mode: 0644]
postfix/man/man1/postconf.1
postfix/man/man5/postconf.5
postfix/man/man5/transport.5
postfix/mantools/postlink
postfix/proto/PACKAGE_README.html
postfix/proto/QSHAPE_README.html
postfix/proto/RESTRICTION_CLASS_README.html
postfix/proto/SMTPD_ACCESS_README.html
postfix/proto/postconf.proto
postfix/proto/transport
postfix/src/global/mail_version.h
postfix/src/postconf/postconf.c
postfix/src/smtpd/Makefile.in

index ef5fe0553f5430164bba66059bc1e4f1109ac81e..937c7091e1cb1069986789e0f2e7d36b0a79ba32 100644 (file)
@@ -97,10 +97,6 @@ navigate faster.
 The PORTING file discusses how to go about porting Postfix to other
 UNIX platforms.
 
-The TODO file lists things that still need to be done. If you want
-to set your teeth into one of those problems, drop me a note at
-wietse@porcupine.org to avoid duplication of effort.
-
 Documentation:
 
     README_FILES/      Instructions for specific Postfix features
@@ -123,6 +119,7 @@ Command-line utilities:
     src/postalias/     Alias database management
     src/postcat/       List Postfix queue file
     src/postconf/      Configuration utility
+    src/postdrop/      Postfix mail submission program
     src/postfix/       Postfix administrative interface
     src/postkick/      Postfix IPC for shell scripts
     src/postlock/      Postfix locking for shell scripts
index dcbb679f9fbf54df1f47374c4d37dcd12fe12f97..2ca445ae20b6d34f49fb2536e36483ac4f853453 100644 (file)
@@ -85,12 +85,14 @@ I\bIn\bns\bst\bta\bal\bll\bli\bin\bng\bg a\ba p\bpr\bre\be-\b-b\bbu\bui\bil\blt\bt P\bPo\bos\bst\btf\bfi\b
   * Create the necessary mail_owner account and setgid_group group for
     exclusive use by Postfix.
 
-  * Execute the post-install script in the Postfix configuration directory to
-    set ownership and permission of Postfix files and directories. Specify any
-    non-default settings for mail_owner or setgid_group on the post-install
-    command line:
+  * Execute the postfix command to set ownership and permission of Postfix
+    files and directories, and to update Postfix configuration files. If
+    necessary, specify any non-default settings for mail_owner or setgid_group
+    on the postfix command line:
 
-    # sh post-install upgrade-package setgid_group=xxx mail_owner=yyy
+    # postfix set-permissions upgrade-configuration \
+           setgid_group=xxx mail_owner=yyy
 
-    This will also update the main.cf and master.cf files if necessary.
+    With Postfix versions before 2.1 you achieve the same result by invoking
+    the post-install script directly.
 
index 0a0c8f961365a7ee68f49b6c8823a2cd400dc34d..fc04162d5af8616650d8eba1e6d22e0ba5bb8c2e 100644 (file)
@@ -4,13 +4,15 @@ P\bPo\bos\bst\btf\bfi\bix\bx B\bBo\bot\btt\btl\ble\ben\bne\bec\bck\bk A\bAn\bna\bal\bly\bys\bsi\bis\bs
 
 P\bPu\bur\brp\bpo\bos\bse\be o\bof\bf t\bth\bhi\bis\bs d\bdo\boc\bcu\bum\bme\ben\bnt\bt
 
-This document describes the "qshape" program which helps the administrator
+This document describes the qshape(1) program which helps the administrator
 understand the Postfix queue message distribution sorted by time and by sender
-or recipient domain. qshape is bundled with the Postfix 2.1 source under the
-"auxiliary" directory. In order to understand the output of qshape, it useful
-to understand the various Postfix queues. To this end the role of each Postfix
-queue directory is described briefly in the "Background info: Postfix queue
-directories" section near the end of this document.
+or recipient domain. qshape(1) is bundled with the Postfix 2.1 source under the
+"auxiliary" directory.
+
+In order to understand the output of qshape(1), it useful to understand the
+various Postfix queues. To this end the role of each Postfix queue directory is
+described briefly in the "Background info: Postfix queue directories" section
+near the end of this document.
 
 This document covers the following topics:
 
@@ -32,8 +34,8 @@ This document covers the following topics:
 
 I\bIn\bnt\btr\bro\bod\bdu\buc\bci\bin\bng\bg t\bth\bhe\be q\bqs\bsh\bha\bap\bpe\be t\bto\boo\bol\bl
 
-When mail is draining slowly or the queue is unexpectedly large, run "qshape"
-as the super-user (root) to help zero in on the problem. The "qshape" program
+When mail is draining slowly or the queue is unexpectedly large, run qshape(1)
+as the super-user (root) to help zero in on the problem. The qshape(1) program
 displays a tabular view of the Postfix queue contents.
 
   * On the horizontal axis, it displays the queue age with fine granularity for
@@ -133,7 +135,7 @@ suggest strategies to reduce congestion.
     $ egrep 'qmgr.*(panic|fatal|error|warning):' /var/log/maillog
 
 When all else fails try the Postfix mailing list for help, but please don't
-forget to include the top 10 or 20 lines of "qshape" output.
+forget to include the top 10 or 20 lines of qshape(1) output.
 
 E\bEx\bxa\bam\bmp\bpl\ble\be 1\b1:\b: H\bHe\bea\bal\blt\bth\bhy\by q\bqu\bue\beu\bue\be
 
@@ -188,7 +190,7 @@ The domains shown are mostly bulk-mailers and all the volume is the tail end of
 the time distribution, showing that short term arrival rates are moderate.
 Larger numbers and lower message ages are more indicative of current trouble.
 Old mail still going nowhere is largely harmless so long as the active and
-incoming queues are short. We can also see that the groups.msg.com
+incoming queues are short. We can also see that the groups.msn.com
 undeliverables are low rate steady stream rather than a concentrated dictionary
 attack that is now over.
 
@@ -214,7 +216,7 @@ Congestion was reported with the active and incoming queues large and not
 shrinking despite very large delivery agent process limits. The thread is
 archived at: http://groups.google.com/groups?th=636626c645f5bbde
 
-Using an older version of "qshape" it was quickly determined that all the
+Using an older version of qshape(1) it was quickly determined that all the
 messages were for just a few destinations:
 
     $ qshape        (show incoming and active queue status)
@@ -597,6 +599,6 @@ strategies) to reduce the chances of repeated complete deferred queue flushes.
 
 C\bCr\bre\bed\bdi\bit\bts\bs
 
-The "qshape" program was developed by Victor Duchovni of Morgan Stanley, who
+The qshape(1) program was developed by Victor Duchovni of Morgan Stanley, who
 also wrote the initial version of this document.
 
index 7b62659cee82f4926f410de7388bdf6aa4d73eba..0dc53a08d3c0d74d61b5179159a44df4724eb5e0 100644 (file)
@@ -65,7 +65,8 @@ SMTP client IP address, and therefore is subject to IP spoofing.
             ...the usual stuff...
 
     /etc/postfix/access:
-        all     permit_mynetworks,reject
+        all@my.domain   permit_mynetworks,reject
+        all@my.hostname permit_mynetworks,reject
 
 Specify d\bdb\bbm\bm instead of h\bha\bas\bsh\bh if your system uses d\bdb\bbm\bm files instead of d\bdb\bb files.
 To find out what map types Postfix supports, use the command p\bpo\bos\bst\btc\bco\bon\bnf\bf -\b-m\bm.
index 26fcbe6112570061246bc5f241f5d2d313fb3dc4..3e442b0c6f86e7138bbfff78190e57763af1a68c 100644 (file)
@@ -77,29 +77,29 @@ apply to all SMTP mail.
     SMTPD_PROXY_README document. This happens while Postfix receives mail,
     before it is stored in the incoming queue.
 
-  * Require that the client sends the HELO or EHLO command before sending the
+  * Requiring that the client sends the HELO or EHLO command before sending the
     MAIL FROM or ETRN command. This may cause problems with home-grown
     applications that send mail. For this reason, the requirement is disabled
     by default ("smtpd_helo_required = no").
 
-  * Disallow illegal syntax in MAIL FROM or RCPT TO commands. This may cause
+  * Disallowing illegal syntax in MAIL FROM or RCPT TO commands. This may cause
     problems with home-grown applications that send mail, and with ancient PC
     mail clients. For this reason, the requirement is disabled by default
     ("strict_rfc821_envelopes = no").
 
-      o Disallow RFC 822 address syntax (example: "MAIL FROM: the dude
+      o Disallowing RFC 822 address syntax (example: "MAIL FROM: the dude
         <dude@example.com>").
 
-      o Disallow addresses that are not enclosed with <> (example: "MAIL FROM:
-        dude@example.com").
+      o Disallowing addresses that are not enclosed with <> (example: "MAIL
+        FROM: dude@example.com").
 
-  * Reject mail from a non-existent sender address. This form of egress
+  * Rejecting mail from a non-existent sender address. This form of egress
     filtering helps to slow down worms and other malware, but may cause
     problems with home-grown software that sends out mail software with an
     unreplyable address. For this reason the requirement is disabled by default
     ("smtpd_reject_unlisted_sender = no").
 
-  * Reject mail for a non-existent recipient address. This form of ingress
+  * Rejecting mail for a non-existent recipient address. This form of ingress
     filtering helps to keep the mail queue free of undeliverable MAILER-DAEMON
     messages. This requirement is enabled by default
     ("smtpd_reject_unlisted_recipient = yes").
similarity index 97%
rename from postfix/RELEASE_NOTES-2.2
rename to postfix/RELEASE_NOTES-2.1
index ddc2aa428467d40dc3720c1a299c9df558f95c68..87e3d5b1d46448d8a363921e0ebbb8b2d6e41a65 100644 (file)
@@ -5,19 +5,19 @@ incompatibility.
 
 The official Postfix release is called 2.1.x where 2=major release
 number, 1=minor release number, x=patchlevel.  Snapshot releases
-are now called 2.2-yyyymmdd where yyyymmdd is the release date
-(yyyy=year, mm=month, dd=day).  The mail_release_date configuration
-parameter contains the release date (both for official release and
-snapshot release).  Patches are issued for the official release
-and change the patchlevel and the release date. Patches are never
-issued for snapshot releases.
+are called 2.2-yyyymmdd where yyyymmdd is the release date (yyyy=year,
+mm=month, dd=day).  The mail_release_date configuration parameter
+contains the release date (both for official release and snapshot
+release).  Patches are issued for the official release and change
+the patchlevel and the release date. Patches are never issued for
+snapshot releases.
 
 Major changes - critical
 ------------------------
 
-You must stop Postfix 1.x before upgrading. This is because the
-master-child protocols have changed, and nothing will work with
-the old master daemon process.
+If you run Postfix 1.x or earlier then you must stop Postfix before
+upgrading. This is because the master-child protocols have changed,
+and very little will work with the old master daemon process.
 
 [Incompat 20021119] You can upgrade Postfix 2.0 without stopping.
 After upgrading an existing Postfix 2.0 system you must use "postfix
diff --git a/postfix/TODO-BEFORE-RELEASE b/postfix/TODO-BEFORE-RELEASE
deleted file mode 100644 (file)
index 9a311b8..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-Documentation needed before official release:
-=============================================
-
-- RELEASE_NOTES file with all changes since Postfix version 2.0.
-
-Tools cleanup
-=============
-
-Remove mantools script for 2.0 to 2.1 migration:
-
-    docparam docuseparam double makepostconf makepostconflinks
-    readme2html specmiss spell useparam user2var var2user
-
-Functionality to be removed before official release:
-====================================================
-
-- The anvil daemon. Its user interface needs to evolve.
-
-    find . type f -print | xargs grep -i anvil
-
-- The tcp_table dictionary type. It's a weak protocol, and the
-SMTPD policy delegation protocol provides a superior mechanism.
-
-    find . type f -print | xargs egrep -i 'tcp_table|tcp-based'
-
-- Change top-level Makefile.stable/snapshot, makedefs.stable/snapshot
-
-- Delete TODO-BEFORE-RELEASE :-)
index a6da7df7ed5006bcfaace6fc326b7565deb11fc9..7f48a82f7867fab76450a5858939dc24603c30dc 100644 (file)
@@ -325,6 +325,7 @@ $html_directory/postlog.1.html:f:root:-:644
 $html_directory/postmap.1.html:f:root:-:644
 $html_directory/postqueue.1.html:f:root:-:644
 $html_directory/postsuper.1.html:f:root:-:644
+$html_directory/qshape.1.html:f:root:-:644
 $html_directory/proxymap.8.html:f:root:-:644
 $html_directory/qmgr.8.html:f:root:-:644
 $html_directory/qmqp-sink.1.html:f:root:-:644
index b3f011d3716ca3d3a92b9a6b0a0662731694bad4..9f6265515e5896dfeee1e8682372af6f2f2e079a 100644 (file)
 #        a  domain  name  hierarchy, as described in section "TABLE
 #        LOOKUP".
 # 
-#        The result is of the form transport:nexthop.   The  trans-
-#        port  field  specifies  a  mail delivery transport such as
-#        smtp or local. The nexthop field specifies where  and  how
-#        to deliver mail. More details are given in section "RESULT
-#        FORMAT".
+#        The result is of the form transport:nexthop and  specifies
+#        how or where to deliver mail. This is described in section
+#        "RESULT FORMAT".
 # 
 # TABLE LOOKUP
 #        With lookups from indexed files such as DB or DBM, or from
 #        mon@hostname).
 # 
 # RESULT FORMAT
-#        The  transport field specifies the name of a mail delivery
+#        The  lookup  result is of the form transport:nexthop.  The
+#        transport field specifies a mail delivery  transport  such
+#        as  smtp  or  local. The nexthop field specifies where and
+#        how to deliver mail.
+# 
+#        The transport field specifies the name of a mail  delivery
 #        transport (the first name of a mail delivery service entry
 #        in the Postfix master.cf file).
 # 
-#        The  interpretation  of  the  nexthop  field  is transport
-#        dependent. In the case of SMTP, specify host:service for a
-#        non-default  server port, and use [host] or [host]:port in
-#        order to disable MX (mail exchanger) DNS lookups.  The  []
+#        The interpretation  of  the  nexthop  field  is  transport
+#        dependent.  In  the  case  of SMTP, specify a service on a
+#        non-default port as host:service,  and  disable  MX  (mail
+#        exchanger)  DNS lookups with [host] or [host]:port. The []
 #        form is required when you specify an IP address instead of
 #        a hostname.
 # 
-#        A null transport and null nexthop  result  means  "do  not
-#        change":  use  the delivery transport and nexthop informa-
-#        tion that would be used when the  entire  transport  table
+#        A  null  transport  and  null nexthop result means "do not
+#        change": use the delivery transport and  nexthop  informa-
+#        tion  that  would  be used when the entire transport table
 #        did not exist.
 # 
-#        A  non-null  transport  field  with  a  null nexthop field
+#        A non-null transport  field  with  a  null  nexthop  field
 #        resets the nexthop information to the recipient domain.
 # 
-#        A null transport field with non-null  nexthop  field  does
+#        A  null  transport  field with non-null nexthop field does
 #        not modify the transport information.
 # 
 # EXAMPLES
-#        In  order to deliver internal mail directly, while using a
-#        mail relay for all other mail, specify a  null  entry  for
-#        internal  destinations  (do not change the delivery trans-
-#        port or the nexthop information) and  specify  a  wildcard
+#        In order to deliver internal mail directly, while using  a
+#        mail  relay  for  all other mail, specify a null entry for
+#        internal destinations (do not change the  delivery  trans-
+#        port  or  the  nexthop information) and specify a wildcard
 #        for all other destinations.
 # 
 #             my.domain    :
 #             .my.domain   :
 #             *         smtp:outbound-relay.my.domain
 # 
-#        In  order  to send mail for foo.org and its subdomains via
-#        the uucp transport to the UUCP host named foo:
+#        In order to send mail for example.com and  its  subdomains
+#        via the uucp transport to the UUCP host named example:
 # 
-#             foo.org      uucp:foo
-#             .foo.org     uucp:foo
+#             example.com      uucp:example
+#             .example.com     uucp:example
 # 
-#        When no nexthop host name is  specified,  the  destination
-#        domain  name  is  used instead. For example, the following
-#        directs mail for user@foo.org via the slow transport to  a
-#        mail  exchanger  for foo.org.  The slow transport could be
-#        something that runs at most  one  delivery  process  at  a
-#        time:
+#        When  no  nexthop  host name is specified, the destination
+#        domain name is used instead. For  example,  the  following
+#        directs  mail  for user@example.com via the slow transport
+#        to a mail exchanger for example.com.  The  slow  transport
+#        could be configured to run at most one delivery process at
+#        time:
 # 
-#             foo.org      slow:
+#             example.com      slow:
 # 
 #        When no transport is specified, Postfix uses the transport
-#        that matches the address domain class (see TRANSPORT FIELD
-#        discussion  above).   The  following  sends  all  mail for
-#        foo.org and its subdomains to host gateway.foo.org:
+#        that  matches  the  address  domain class (see DESCRIPTION
+#        above).  The following sends all mail for example.com  and
+#        its subdomains to host gateway.example.com:
 # 
-#             foo.org      :[gateway.foo.org]
-#             .foo.org     :[gateway.foo.org]
+#             example.com      :[gateway.example.com]
+#             .example.com     :[gateway.example.com]
 # 
-#        In the above example, the  []  are  used  to  suppress  MX
-#        lookups.   The  result  would  likely  point to your local
-#        machine.
+#        In  the  above  example, the [] suppress MX lookups.  This
+#        prevents mail routing loops when your machine  is  primary
+#        MX host for example.com.
 # 
-#        In the case of delivery via SMTP, one  may  specify  host-
+#        In  the  case  of delivery via SMTP, one may specify host-
 #        name:service instead of just a host:
 # 
-#             foo.org      smtp:bar.org:2025
+#             example.com      smtp:bar.example:2025
 # 
-#        This  directs  mail  for user@foo.org to host bar.org port
-#        2025. Instead of a numerical port a symbolic name  may  be
-#        used.  Specify  [] around the hostname in order to disable
-#        MX lookups.
+#        This directs mail for user@example.com to host bar.example
+#        port 2025. Instead of a numerical port a symbolic name may
+#        be used. Specify [] around the hostname if MX lookups must
+#        be disabled.
 # 
 #        The error mailer can be used to bounce mail:
 # 
-#             .foo.org      error:mail for *.foo.org is not  deliv-
-#        erable
+#             .example.com      error:mail for *.example.com is not
+#        deliverable
 # 
-#        This  causes  all  mail  for  user@anything.foo.org  to be
+#        This causes all mail for user@anything.example.com  to  be
 #        bounced.
 # 
 # REGULAR EXPRESSION TABLES
-#        This section describes how the table lookups  change  when
+#        This  section  describes how the table lookups change when
 #        the table is given in the form of regular expressions. For
-#        a description of regular expression lookup  table  syntax,
+#        a  description  of regular expression lookup table syntax,
 #        see regexp_table(5) or pcre_table(5).
 # 
-#        Each  pattern  is  a regular expression that is applied to
-#        the   entire    address    being    looked    up.    Thus,
-#        some.domain.hierarchy  is  not  looked  up  via its parent
-#        domains, nor is user+foo@domain looked up as  user@domain.
+#        Each pattern is a regular expression that  is  applied  to
+#        the    entire    address    being    looked    up.   Thus,
+#        some.domain.hierarchy is not  looked  up  via  its  parent
+#        domains,  nor is user+foo@domain looked up as user@domain.
 # 
-#        Patterns  are  applied  in  the  order as specified in the
-#        table, until a pattern is found that  matches  the  search
+#        Patterns are applied in the  order  as  specified  in  the
+#        table,  until  a  pattern is found that matches the search
 #        string.
 # 
-#        Results  are  the  same as with indexed file lookups, with
-#        the additional feature that parenthesized substrings  from
+#        Results are the same as with indexed  file  lookups,  with
+#        the  additional feature that parenthesized substrings from
 #        the pattern can be interpolated as $1, $2 and so on.
 # 
 # TCP-BASED TABLES
-#        This  section  describes how the table lookups change when
+#        This section describes how the table lookups  change  when
 #        lookups are directed to a TCP-based server. For a descrip-
-#        tion   of  the  TCP  client/server  lookup  protocol,  see
-#        tcp_table(5).  This feature is not  available  in  Postfix
+#        tion  of  the  TCP  client/server  lookup  protocol,   see
+#        tcp_table(5).   This  feature  is not available in Postfix
 #        version 2.1.
 # 
-#        Each  lookup  operation  uses the entire recipient address
-#        once.  Thus, some.domain.hierarchy is not  looked  up  via
-#        its  parent  domains,  nor is user+foo@domain looked up as
+#        Each lookup operation uses the  entire  recipient  address
+#        once.   Thus,  some.domain.hierarchy  is not looked up via
+#        its parent domains, nor is user+foo@domain  looked  up  as
 #        user@domain.
 # 
 #        Results are the same as with indexed file lookups.
 # 
 # CONFIGURATION PARAMETERS
-#        The following main.cf parameters are especially  relevant.
-#        The  text  below  provides  only  a parameter summary. See
+#        The  following main.cf parameters are especially relevant.
+#        The text below provides  only  a  parameter  summary.  See
 #        postconf(5) for more details including examples.
 # 
 #        empty_address_recipient
-#               The address that is looked up instead of  the  null
+#               The  address  that is looked up instead of the null
 #               sender address.
 # 
 #        parent_domain_matches_subdomains
-#               List  of  Postfix features that use domain.tld pat-
-#               terns  to  match  sub.domain.tld  (as  opposed   to
+#               List of Postfix features that use  domain.tld  pat-
+#               terns   to  match  sub.domain.tld  (as  opposed  to
 #               requiring .domain.tld patterns).
 # 
 #        transport_maps
 #        postmap(1), Postfix lookup table manager
 # 
 # README FILES
-#        Use  "postconf  readme_directory" or "postconf html_direc-
+#        Use "postconf readme_directory" or  "postconf  html_direc-
 #        tory" to locate this information.
 #        DATABASE_README, Postfix lookup table overview
 #        FILTER_README, external content filter
 # 
 # LICENSE
-#        The Secure Mailer license must be  distributed  with  this
+#        The  Secure  Mailer  license must be distributed with this
 #        software.
 # 
 # AUTHOR(S)
index e7a7fc3df2e99d682c6732cf425786e2c264741b..043407236179d9abfbdad0fc9e3ee8a84ddcf871 100644 (file)
@@ -11,7 +11,8 @@ COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
        postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
        postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
        postqueue.1.html postsuper.1.html smtp-source.1.html \
-       smtp-sink.1.html qmqp-source.1.html qmqp-sink.1.html
+       smtp-sink.1.html qmqp-source.1.html qmqp-sink.1.html \
+       qshape.1.html
 CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \
        transport.5.html virtual.5.html pcre_table.5.html regexp_table.5.html \
        cidr_table.5.html tcp_table.5.html header_checks.5.html \
@@ -201,6 +202,10 @@ qmqp-sink.1.html: ../src/smtpstone/qmqp-sink.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
 
+qshape.1.html: ../auxiliary/qshape/qshape.pl
+       PATH=../mantools:$$PATH; \
+       srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+
 access.5.html: ../proto/access
        PATH=../mantools:$$PATH; \
        srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
index 19027e3b53eb0f6d153f8f0303a144ce3fc75032..3aa2a93612284128563b7ebe317b1ef2331f495d 100644 (file)
@@ -118,17 +118,18 @@ on non-Postfix directories that need to be created in the process.
 <li> <p> Create the necessary <a href="postconf.5.html#mail_owner">mail_owner</a> account and <a href="postconf.5.html#setgid_group">setgid_group</a>
 group for exclusive use by Postfix. </p>
 
-<li> <p> Execute the post-install script in the Postfix configuration
-directory to set ownership and permission of Postfix files and
-directories. Specify any non-default settings for <a href="postconf.5.html#mail_owner">mail_owner</a> or
-<a href="postconf.5.html#setgid_group">setgid_group</a> on the post-install command line: </p>
+<li> <p> Execute the postfix command to set ownership and permission
+of Postfix files and directories, and to update Postfix configuration
+files. If necessary, specify any non-default settings for <a href="postconf.5.html#mail_owner">mail_owner</a>
+or <a href="postconf.5.html#setgid_group">setgid_group</a> on the postfix command line: </p>
 
 <pre>
-# sh post-install upgrade-package <a href="postconf.5.html#setgid_group">setgid_group</a>=xxx <a href="postconf.5.html#mail_owner">mail_owner</a>=yyy
+# postfix set-permissions upgrade-configuration \
+       <a href="postconf.5.html#setgid_group">setgid_group</a>=xxx <a href="postconf.5.html#mail_owner">mail_owner</a>=yyy
 </pre>
 
-<p> This will also update the main.cf and master.cf files if
-necessary. </p>
+<p> With Postfix versions before 2.1 you achieve the same result
+by invoking the post-install script directly. </p>
 
 </ul>
 
index ba9f161cc3ca79adf6c0c0f657f964b61cb7ec76..c15d95efdc6f0e6c3a0afa7c449709c814cf027a 100644 (file)
 
 <h2>Purpose of this document </h2>
 
-<p> This document describes the "qshape" program which helps the
+<p> This document describes the <a href="qshape.1.html">qshape(1)</a> program which helps the
 administrator understand the Postfix queue message distribution
-sorted by time and by sender or recipient domain. qshape is bundled
-with the Postfix 2.1 source under the "auxiliary" directory. In
-order to understand the output of qshape, it useful to understand
-the various Postfix queues. To this end the role of each Postfix
-queue directory is described briefly in the "Background info:
-Postfix queue directories" section near the end of this document.
+sorted by time and by sender or recipient domain. <a href="qshape.1.html">qshape(1)</a> is
+bundled with the Postfix 2.1 source under the "auxiliary" directory.
 </p>
 
+<p> In order to understand the output of <a href="qshape.1.html">qshape(1)</a>, it useful to
+understand the various Postfix queues. To this end the role of each
+Postfix queue directory is described briefly in the "Background
+info:  Postfix queue directories" section near the end of this
+document.  </p>
+
 <p> This document covers the following topics: </p>
 
 <ul>
@@ -71,8 +73,8 @@ queue</a></li>
 
 
 <p> When mail is draining slowly or the queue is unexpectedly large,
-run "qshape" as the super-user (root) to help zero in on the problem.
-The "qshape" program displays a tabular view of the Postfix queue
+run <a href="qshape.1.html">qshape(1)</a> as the super-user (root) to help zero in on the problem.
+The <a href="qshape.1.html">qshape(1)</a> program displays a tabular view of the Postfix queue
 contents.  </p>
 
 <ul>
@@ -217,7 +219,7 @@ $ egrep 'qmgr.*(panic|fatal|error|warning):' /var/log/maillog
 </blockquote>
 
 <p> When all else fails try the Postfix mailing list for help, but
-please don't forget to include the top 10 or 20 lines of "qshape"
+please don't forget to include the top 10 or 20 lines of <a href="qshape.1.html">qshape(1)</a>
 output.  </p>
 
 <h2><a name="healthy">Example 1: Healthy queue</a></h2>
@@ -290,7 +292,7 @@ is the tail end of the time distribution, showing that short term
 arrival rates are moderate. Larger numbers and lower message ages
 are more indicative of current trouble. Old mail still going nowhere
 is largely harmless so long as the active and <a href="QSHAPE_README.html#incoming_queue">incoming queues</a> are
-short. We can also see that the groups.msg.com undeliverables are
+short. We can also see that the groups.msn.com undeliverables are
 low rate steady stream rather than a concentrated dictionary attack
 that is now over. </p>
 
@@ -322,7 +324,7 @@ queues large and not shrinking despite very large delivery agent
 process limits.  The thread is archived at:
 <a href="http://groups.google.com/groups?th=636626c645f5bbde">http://groups.google.com/groups?th=636626c645f5bbde</a> </p>
 
-<p> Using an older version of "qshape" it was quickly determined
+<p> Using an older version of <a href="qshape.1.html">qshape(1)</a> it was quickly determined
 that all the messages were for just a few destinations: </p>
 
 <blockquote>
@@ -780,7 +782,7 @@ queue flushes.  </p>
 
 <h2><a name="credits">Credits</a></h2>
 
-<p> The "qshape" program was developed by Victor Duchovni of Morgan
+<p> The <a href="qshape.1.html">qshape(1)</a> program was developed by Victor Duchovni of Morgan
 Stanley, who also wrote the initial version of this document.  </p>
 
 </body>
index cf184e253f5b2c9043fa11bcebfdc7472f085e59..836ca79c8edbabe806f66f01fa873877ca9e285d 100644 (file)
@@ -105,7 +105,8 @@ to IP spoofing. </p>
         <i>...the usual stuff...</i>
 
 /etc/postfix/access:
-    all     <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject
+    all@my.domain   <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject
+    all@my.hostname <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject
 </pre>
 </blockquote>
 
index 130b11dfdd6580b22a4b2cc639d2d433103bc10a..3435f7ef2de0b30beb913c3698d6656c2d461a3d 100644 (file)
@@ -122,13 +122,13 @@ the <a href="QSHAPE_README.html#incoming_queue">incoming queue</a>.  </p>
 in the <a href="SMTPD_PROXY_README.html">SMTPD_PROXY_README</a> document.  This happens while Postfix
 receives mail, before it is stored in the <a href="QSHAPE_README.html#incoming_queue">incoming queue</a>.  </p>
 
-<li> <p> Require that the client sends the HELO or EHLO command
+<li> <p> Requiring that the client sends the HELO or EHLO command
 before sending the MAIL FROM or ETRN command. This may cause problems
 with home-grown applications that send mail.  For this reason, the
 requirement is disabled by default ("<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = no").
 </p>
 
-<li> <p> Disallow illegal syntax in MAIL FROM or RCPT TO commands.
+<li> <p> Disallowing illegal syntax in MAIL FROM or RCPT TO commands.
 This may cause problems with home-grown applications that send
 mail, and with ancient PC mail clients.  For this reason, the
 requirement is disabled by default ("<a href="postconf.5.html#strict_rfc821_envelopes">strict_rfc821_envelopes</a> =
@@ -136,21 +136,21 @@ no").  </p>
 
 <ul>
 
-<li> <p> Disallow <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> address syntax (example: "MAIL FROM: the
+<li> <p> Disallowing <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> address syntax (example: "MAIL FROM: the
 dude &lt;dude@example.com&gt;"). </p>
 
-<li> <p> Disallow addresses that are not enclosed with &lt;&gt;
+<li> <p> Disallowing addresses that are not enclosed with &lt;&gt;
 (example: "MAIL FROM: dude@example.com"). </p>
 
 </ul>
 
-<li> <p> Reject mail from a non-existent sender address.  This form
+<li> <p> Rejecting mail from a non-existent sender address.  This form
 of egress filtering helps to slow down worms and other malware, but
 may cause problems with home-grown software that sends out mail
 software with an unreplyable address. For this reason the requirement
 is disabled by default ("<a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> = no").  </p>
 
-<li> <p> Reject mail for a non-existent recipient address.  This
+<li> <p> Rejecting mail for a non-existent recipient address.  This
 form of ingress filtering helps to keep the mail queue free of
 undeliverable MAILER-DAEMON messages. This requirement is enabled
 by default ("<a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> = yes"). </p>
index 67cbe86df021c7c3ce71544717e5df3cb87608ab..32d152b0a1c4086b6c06bd18f304842866d9e452 100644 (file)
@@ -108,7 +108,7 @@ their default settings. </p>
 2     <a href="postconf.5.html#myorigin">myorigin</a> = $<a href="postconf.5.html#mydomain">mydomain</a>
 3     <a href="postconf.5.html#relayhost">relayhost</a> = $<a href="postconf.5.html#mydomain">mydomain</a>
 4     <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = 127.0.0.1
-5     <a href="postconf.5.html#local_transport">local_transport</a> = error:local delivery is disabled
+5     <a href="postconf.5.html#local_transport">local_transport</a> = <a href="error.8.html">error</a>:local delivery is disabled
 6 
 7 /etc/postfix/master.cf:
 8     Comment out the local delivery agent entry
@@ -282,7 +282,7 @@ harder to break. </p>
 2     <a href="postconf.5.html#myorigin">myorigin</a> = example.com
 3     <a href="postconf.5.html#mydestination">mydestination</a> =
 4     <a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> =
-5     <a href="postconf.5.html#local_transport">local_transport</a> = error:local mail delivery is disabled
+5     <a href="postconf.5.html#local_transport">local_transport</a> = <a href="error.8.html">error</a>:local mail delivery is disabled
 6 
 7 /etc/postfix/master.cf:
 8     Comment out the local delivery agent
index c2e837498499f1e60c47d1b86ddab35ee5ddefe9..0398b2c0b2aa4143061ffccf23852cc33e67a16b 100644 (file)
@@ -118,24 +118,30 @@ POSTCONF(1)                                           POSTCONF(1)
                      always  returns  the string <b>foobar</b> as lookup
                      result.
 
+              <b>tcp</b> (read-only)
+                     Perform lookups using a simple request-reply
+                     protocol  that is described in <a href="tcp_table.5.html">tcp_table(5)</a>.
+                     This feature is not  included  with  Postfix
+                     2.1.
+
               <b>unix</b> (read-only)
-                     A limited way to query the UNIX  authentica-
+                     A  limited way to query the UNIX authentica-
                      tion  database.  The  following  tables  are
                      implemented:
 
                      <b>unix:passwd.byname</b>
-                             The  table  is  the  UNIX   password
-                             database.  The  key is a login name.
-                             The result is a password file  entry
+                             The   table  is  the  UNIX  password
+                             database. The key is a  login  name.
+                             The  result is a password file entry
                              in passwd(5) format.
 
                      <b>unix:group.byname</b>
-                             The   table   is   the   UNIX  group
-                             database. The key is a  group  name.
-                             The  result is a group file entry in
+                             The  table   is   the   UNIX   group
+                             database.  The  key is a group name.
+                             The result is a group file entry  in
                              group(5) format.
 
-       Other table types may exist depending on how  Postfix  was
+       Other  table  types may exist depending on how Postfix was
        built.
 
        <b>-n</b>     Print parameter settings that are not left at their
@@ -143,7 +149,7 @@ POSTCONF(1)                                           POSTCONF(1)
               specified in main.cf.
 
        <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
-              tiple <b>-v</b> options  make  the  software  increasingly
+              tiple  <b>-v</b>  options  make  the software increasingly
               verbose.
 
 <b>DIAGNOSTICS</b>
@@ -154,14 +160,14 @@ POSTCONF(1)                                           POSTCONF(1)
               Directory with Postfix configuration files.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The  following  <b>main.cf</b> parameters are especially relevant
+       The following <b>main.cf</b> parameters are  especially  relevant
        to this program.
 
-       The text below provides  only  a  parameter  summary.  See
+       The  text  below  provides  only  a parameter summary. See
        <a href="postconf.5.html">postconf(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix main.cf and
+              The default location of  the  Postfix  main.cf  and
               master.cf configuration files.
 
 <b>FILES</b>
@@ -174,7 +180,7 @@ POSTCONF(1)                                           POSTCONF(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <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 4c02d767e215711b4330127b2fcc18ff5838f860..353fa6d0192ba73fb63d381d9de6e5e4206a2970 100644 (file)
@@ -2245,11 +2245,9 @@ configure or operate a specific Postfix subsystem or feature.
 <DT><b><a name="ignore_mx_lookup_error">ignore_mx_lookup_error</a>
 (default: no)</b></DT><DD>
 
-<p>
-Ignore DNS MX lookups that produce no response.  By default,
-Postfix defers delivery and tries again after some delay.  This
-behavior is required by the SMTP standard.
-</p>
+<p> Ignore DNS MX lookups that produce no response.  By default,
+the Postfix SMTP client defers delivery and tries again after some
+delay.  This behavior is required by the SMTP standard.  </p>
 
 <p>
 Specify "<b><a href="postconf.5.html#ignore_mx_lookup_error">ignore_mx_lookup_error</a> = yes</b>" to force a DNS A record
@@ -5578,12 +5576,10 @@ Skip SMTP servers that greet with a 5XX status code (go away, do
 not try again later).
 </p>
 
-<p>
-By default, Postfix moves on the next mail exchanger. Specify
-"<a href="postconf.5.html#smtp_skip_5xx_greeting">smtp_skip_5xx_greeting</a> = no" if Postfix should bounce the mail
-immediately. The default setting is incorrect, but it is what a
-lot of people expect to happen.
-</p>
+<p> By default, the Postfix SMTP client moves on the next mail
+exchanger. Specify "<a href="postconf.5.html#smtp_skip_5xx_greeting">smtp_skip_5xx_greeting</a> = no" if Postfix should
+bounce the mail immediately. The default setting is incorrect, but
+it is what a lot of people expect to happen.  </p>
 
 
 </DD>
@@ -6605,7 +6601,8 @@ code for rejected requests (default: 554). </dd>
 <dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt>
 
 <dd>Reject the request when the RCPT TO address has no DNS A or MX
-record. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies
+record and Postfix is not final destination for the recipient
+address. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies
 the response code for rejected requests (default: 450).  The response
 is always 450 in case of a temporary DNS error.</dd>
 
@@ -7050,10 +7047,11 @@ Postfix version 2.1 and later. </dd>
 
 <dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt>
 
-<dd>Reject the request when the MAIL FROM address has no DNS A
-or MX record. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter
-specifies the response code for rejected requests (default: 450).
-The response is always 450 in case of a temporary DNS error. </dd>
+<dd>Reject the request when the MAIL FROM address has no DNS A or
+MX record and Postfix is not final destination for the sender
+address. <br> The <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies
+the response code for rejected requests (default: 450).  The response
+is always 450 in case of a temporary DNS error. </dd>
 
 <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>
 
diff --git a/postfix/html/qshape.1.html b/postfix/html/qshape.1.html
new file mode 100644 (file)
index 0000000..506a503
--- /dev/null
@@ -0,0 +1,117 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+<html> <head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+<title> Postfix manual - qshape(1) </title>
+</head> <body> <pre>
+QSHAPE(1)                                               QSHAPE(1)
+
+<b>NAME</b>
+       qshape - Print Postfix queue domain and age distribution
+
+<b>SYNOPSIS</b>
+       <b>qshape</b> [<b>-s</b>] [<b>-p</b>] [<b>-m</b> <i>min</i><b>_</b><i>subdomains</i>]
+               [<b>-b</b> <i>bucket</i><b>_</b><i>count</i>] [<b>-t</b> <i>bucket</i><b>_</b><i>time</i>]
+               [<b>-w</b> <i>terminal</i><b>_</b><i>width</i>]
+               [<b>-c</b> <i>config</i><b>_</b><i>directory</i>] [<i>queue</i><b>_</b><i>name</i> ...]
+
+<b>DESCRIPTION</b>
+       The  <b>qshape</b> program helps the administrator understand the
+       Postfix queue message distribution in time and  by  sender
+       domain  or recipient domain. The program needs read access
+       to the queue directories and queue files, so it  must  run
+       as  the  superuser  or the <b><a href="postconf.5.html#mail_owner">mail_owner</a></b> specified in <i>main.cf</i>
+       (typically <b>postfix</b>).
+
+       Options:
+
+       <b>-s</b>     Display the sender domain distribution  instead  of
+              the  recipient domain distribution.  By default the
+              recipient distribution is displayed. There  can  be
+              more  recipients than messages, but as each message
+              has only one sender, the sender distribution is a a
+              message distribution.
+
+       <b>-p</b>     Generate  aggregate  statistics for parent domains.
+              Top level domains are not shown,  nor  are  domains
+              with  fewer  than  <i>min</i><b>_</b><i>subdomains</i>  subdomains.  The
+              names of parent domains are shown  with  a  leading
+              dot, (e.g. <i>.example.com</i>).
+
+       <b>-m</b> <i>min</i><b>_</b><i>subdomains</i>
+              When used with the <b>-p</b> option, sets the minimum sub-
+              domain count needed to show a separate line  for  a
+              parent domain. The default is 5.
+
+       <b>-b</b> <i>bucket</i><b>_</b><i>count</i>
+              The  age  distribution is broken up into a sequence
+              of geometrically increasing intervals. This  option
+              sets  the  number  of  intervals or "buckets". Each
+              bucket has a maximum queue age  that  is  twice  as
+              large  as  that  of  the  previous bucket. The last
+              bucket has no age limit.
+
+       <b>-b</b> <i>bucket</i><b>_</b><i>time</i>
+              The age limit in minutes for the first time bucket.
+              The  default  value  is  5,  meaning that the first
+              bucket counts messages between 0 and 5 minutes old.
+
+       <b>-w</b> <i>terminal</i><b>_</b><i>width</i>
+              The  output is right justified, with the counts for
+              the last bucket shown on the 80th column, the  <i>ter-</i>
+              <i>minal</i><b>_</b><i>width</i>  can  be  adjusted  for  wider  screens
+              allowing more buckets to be displayed with truncat-
+              ing  the domain names on the left. When a row for a
+              full domain name and its counters does not  fit  in
+              the  specified  number of columns, only the last 17
+              bytes of the domain name are shown with the  prefix
+              replaced  by  a  '+'  character.  Truncated  parent
+              domain rows are shown as '.+' followed by the  last
+              16  bytes  of the domain name. If this is still too
+              narrow to show the domain name and  all  the  coun-
+              ters, the terminal_width limit is violated.
+
+       <b>-c</b> <i>config</i><b>_</b><i>directory</i>
+              The  <b>main.cf</b>  configuration  file  is  in the named
+              directory  instead  of  the  default  configuration
+              directory.
+
+       Arguments:
+
+       <i>queue</i><b>_</b><i>name</i>
+              By  default  <b>qshape</b> displays the combined distribu-
+              tion of the <a href="QSHAPE_README.html#incoming_queue">incoming</a> and <a href="QSHAPE_README.html#active_queue">active queues</a>. To  display
+              a  different  set of queues, just list their direc-
+              tory names on the command line.  Absolute paths are
+              used  as  is, other paths are taken relative to the
+              <i>main.cf</i> <b><a href="postconf.5.html#queue_directory">queue_directory</a></b> parameter  setting.   While
+              <i>main.cf</i>  supports the use of <i>$variable</i> expansion in
+              the definition of  the  <b><a href="postconf.5.html#queue_directory">queue_directory</a></b>  parameter,
+              the  <b>qshape</b> program does not. If you must use vari-
+              able expansions in the <b><a href="postconf.5.html#queue_directory">queue_directory</a></b> setting, you
+              must  specify  an  explicit  absolute path for each
+              queue subdirectory even if  you  want  the  default
+              <a href="QSHAPE_README.html#incoming_queue">incoming</a> and <a href="QSHAPE_README.html#active_queue">active queue</a> distribution.
+
+<b>SEE ALSO</b>
+       <a href="mailq.1.html">mailq(1)</a> List all messages in the queue.
+       <a href="QSHAPE_README.html">QSHAPE_README</a> Examples and background material.
+
+<b>FILES</b>
+       $<a href="postconf.5.html#config_directory">config_directory</a>/main.cf, Postfix installation parameters.
+       $<a href="postconf.5.html#queue_directory">queue_directory</a>/maildrop/, local submission directory.
+       $<a href="postconf.5.html#queue_directory">queue_directory</a>/incoming/, new message queue.
+       $<a href="postconf.5.html#queue_directory">queue_directory</a>/hold/, messages waiting for tech support.
+       $<a href="postconf.5.html#queue_directory">queue_directory</a>/active/, messages scheduled for delivery.
+       $<a href="postconf.5.html#queue_directory">queue_directory</a>/deferred/, messages postponed for later delivery.
+
+<b>LICENSE</b>
+       The  Secure  Mailer  license must be distributed with this
+       software.
+
+<b>AUTHOR(S)</b>
+       Victor Duchovni
+       Morgan Stanley
+
+                                                        QSHAPE(1)
+</pre> </body> </html>
index 2e8f826dc14f5e4eb72c1becfbd3db7003e44b37..a6609d7b81dbbf275b5919c78250ef43759c2166 100644 (file)
@@ -81,11 +81,9 @@ TRANSPORT(5)                                         TRANSPORT(5)
        a  domain  name  hierarchy, as described in section "TABLE
        LOOKUP".
 
-       The <i>result</i> is of the form <i>transport</i><b>:</b><i>nexthop</i>.   The  <i>trans-</i>
-       <i>port</i>  field  specifies  a  mail delivery transport such as
-       <b>smtp</b> or <b>local</b>. The <i>nexthop</i> field specifies where  and  how
-       to deliver mail. More details are given in section "RESULT
-       FORMAT".
+       The <i>result</i> is of the form <i>transport:nexthop</i> and  specifies
+       how or where to deliver mail. This is described in section
+       "RESULT FORMAT".
 
 <b>TABLE LOOKUP</b>
        With lookups from indexed files such as DB or DBM, or from
@@ -120,129 +118,134 @@ TRANSPORT(5)                                         TRANSPORT(5)
        mon@hostname).
 
 <b>RESULT FORMAT</b>
-       The  transport field specifies the name of a mail delivery
+       The  lookup  result is of the form <i>transport</i><b>:</b><i>nexthop</i>.  The
+       <i>transport</i> field specifies a mail delivery  transport  such
+       as  <b>smtp</b>  or  <b>local</b>. The <i>nexthop</i> field specifies where and
+       how to deliver mail.
+
+       The transport field specifies the name of a mail  delivery
        transport (the first name of a mail delivery service entry
        in the Postfix <b>master.cf</b> file).
 
-       The  interpretation  of  the  nexthop  field  is transport
-       dependent. In the case of SMTP, specify <i>host</i>:<i>service</i> for a
-       non-default  server port, and use [<i>host</i>] or [<i>host</i>]:<i>port</i> in
-       order to disable MX (mail exchanger) DNS lookups.  The  []
+       The interpretation  of  the  nexthop  field  is  transport
+       dependent.  In  the  case  of SMTP, specify a service on a
+       non-default port as <i>host</i>:<i>service</i>,  and  disable  MX  (mail
+       exchanger)  DNS lookups with [<i>host</i>] or [<i>host</i>]:<i>port</i>. The []
        form is required when you specify an IP address instead of
        a hostname.
 
-       A null <i>transport</i> and null <i>nexthop</i>  result  means  "do  not
-       change":  use  the delivery transport and nexthop informa-
-       tion that would be used when the  entire  transport  table
+       A  null  <i>transport</i>  and  null <i>nexthop</i> result means "do not
+       change": use the delivery transport and  nexthop  informa-
+       tion  that  would  be used when the entire transport table
        did not exist.
 
-       A  non-null  <i>transport</i>  field  with  a  null <i>nexthop</i> field
+       A non-null <i>transport</i>  field  with  a  null  <i>nexthop</i>  field
        resets the nexthop information to the recipient domain.
 
-       A null <i>transport</i> field with non-null  <i>nexthop</i>  field  does
+       A  null  <i>transport</i>  field with non-null <i>nexthop</i> field does
        not modify the transport information.
 
 <b>EXAMPLES</b>
-       In  order to deliver internal mail directly, while using a
-       mail relay for all other mail, specify a  null  entry  for
-       internal  destinations  (do not change the delivery trans-
-       port or the nexthop information) and  specify  a  wildcard
+       In order to deliver internal mail directly, while using  a
+       mail  relay  for  all other mail, specify a null entry for
+       internal destinations (do not change the  delivery  trans-
+       port  or  the  nexthop information) and specify a wildcard
        for all other destinations.
 
             <b>my.domain    :</b>
             <b>.my.domain   :</b>
             <b>*         <a href="smtp.8.html">smtp</a>:outbound-relay.my.domain</b>
 
-       In  order  to send mail for <b>foo.org</b> and its subdomains via
-       the <b>uucp</b> transport to the UUCP host named <b>foo</b>:
+       In order to send mail for <b>example.com</b> and  its  subdomains
+       via the <b>uucp</b> transport to the UUCP host named <b>example</b>:
 
-            <b>foo.org      uucp:foo</b>
-            <b>.foo.org     uucp:foo</b>
+            <b>example.com      uucp:example</b>
+            <b>.example.com     uucp:example</b>
 
-       When no nexthop host name is  specified,  the  destination
-       domain  name  is  used instead. For example, the following
-       directs mail for <i>user</i>@<b>foo.org</b> via the <b>slow</b> transport to  a
-       mail  exchanger  for <b>foo.org</b>.  The <b>slow</b> transport could be
-       something that runs at most  one  delivery  process  at  a
-       time:
+       When  no  nexthop  host name is specified, the destination
+       domain name is used instead. For  example,  the  following
+       directs  mail  for <i>user</i>@<b>example.com</b> via the <b>slow</b> transport
+       to a mail exchanger for <b>example.com</b>.  The  <b>slow</b>  transport
+       could be configured to run at most one delivery process at
+       time:
 
-            <b>foo.org      slow:</b>
+            <b>example.com      slow:</b>
 
        When no transport is specified, Postfix uses the transport
-       that matches the address domain class (see TRANSPORT FIELD
-       discussion  above).   The  following  sends  all  mail for
-       <b>foo.org</b> and its subdomains to host <b>gateway.foo.org</b>:
+       that  matches  the  address  domain class (see DESCRIPTION
+       above).  The following sends all mail for <b>example.com</b>  and
+       its subdomains to host <b>gateway.example.com</b>:
 
-            <b>foo.org      :[gateway.foo.org]</b>
-            <b>.foo.org     :[gateway.foo.org]</b>
+            <b>example.com      :[gateway.example.com]</b>
+            <b>.example.com     :[gateway.example.com]</b>
 
-       In the above example, the  []  are  used  to  suppress  MX
-       lookups.   The  result  would  likely  point to your local
-       machine.
+       In  the  above  example, the [] suppress MX lookups.  This
+       prevents mail routing loops when your machine  is  primary
+       MX host for <b>example.com</b>.
 
-       In the case of delivery via SMTP, one  may  specify  <i>host-</i>
+       In  the  case  of delivery via SMTP, one may specify <i>host-</i>
        <i>name</i>:<i>service</i> instead of just a host:
 
-            <b>foo.org      <a href="smtp.8.html">smtp</a>:bar.org:2025</b>
+            <b>example.com      <a href="smtp.8.html">smtp</a>:bar.example:2025</b>
 
-       This  directs  mail  for <i>user</i>@<b>foo.org</b> to host <b>bar.org</b> port
-       <b>2025</b>. Instead of a numerical port a symbolic name  may  be
-       used.  Specify  [] around the hostname in order to disable
-       MX lookups.
+       This directs mail for <i>user</i>@<b>example.com</b> to host <b>bar.example</b>
+       port <b>2025</b>. Instead of a numerical port a symbolic name may
+       be used. Specify [] around the hostname if MX lookups must
+       be disabled.
 
        The error mailer can be used to bounce mail:
 
-            <b>.foo.org      error:mail for *.foo.org is not  deliv-</b>
-       <b>erable</b>
+            <b>.example.com      <a href="error.8.html">error</a>:mail for *.example.com is not</b>
+       <b>deliverable</b>
 
-       This  causes  all  mail  for  <i>user</i>@<i>anything</i><b>.foo.org</b>  to be
+       This causes all mail for <i>user</i>@<i>anything</i><b>.example.com</b>  to  be
        bounced.
 
 <b>REGULAR EXPRESSION TABLES</b>
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        the table is given in the form of regular expressions. For
-       a description of regular expression lookup  table  syntax,
+       a  description  of regular expression lookup table syntax,
        see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
 
-       Each  pattern  is  a regular expression that is applied to
-       the   entire    address    being    looked    up.    Thus,
-       <i>some.domain.hierarchy</i>  is  not  looked  up  via its parent
-       domains, nor is <i>user+foo@domain</i> looked up as  <i>user@domain</i>.
+       Each pattern is a regular expression that  is  applied  to
+       the    entire    address    being    looked    up.   Thus,
+       <i>some.domain.hierarchy</i> is not  looked  up  via  its  parent
+       domains,  nor is <i>user+foo@domain</i> looked up as <i>user@domain</i>.
 
-       Patterns  are  applied  in  the  order as specified in the
-       table, until a pattern is found that  matches  the  search
+       Patterns are applied in the  order  as  specified  in  the
+       table,  until  a  pattern is found that matches the search
        string.
 
-       Results  are  the  same as with indexed file lookups, with
-       the additional feature that parenthesized substrings  from
+       Results are the same as with indexed  file  lookups,  with
+       the  additional feature that parenthesized substrings from
        the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
 
 <b>TCP-BASED TABLES</b>
-       This  section  describes how the table lookups change when
+       This section describes how the table lookups  change  when
        lookups are directed to a TCP-based server. For a descrip-
-       tion   of  the  TCP  client/server  lookup  protocol,  see
-       <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.  This feature is not  available  in  Postfix
+       tion  of  the  TCP  client/server  lookup  protocol,   see
+       <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.   This  feature  is not available in Postfix
        version 2.1.
 
-       Each  lookup  operation  uses the entire recipient address
-       once.  Thus, <i>some.domain.hierarchy</i> is not  looked  up  via
-       its  parent  domains,  nor is <i>user+foo@domain</i> looked up as
+       Each lookup operation uses the  entire  recipient  address
+       once.   Thus,  <i>some.domain.hierarchy</i>  is not looked up via
+       its parent domains, nor is <i>user+foo@domain</i>  looked  up  as
        <i>user@domain</i>.
 
        Results are the same as with indexed file lookups.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <b>main.cf</b> parameters are especially  relevant.
-       The  text  below  provides  only  a parameter summary. See
+       The  following <b>main.cf</b> parameters are especially relevant.
+       The text below provides  only  a  parameter  summary.  See
        <a href="postconf.5.html">postconf(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a></b>
-              The address that is looked up instead of  the  null
+              The  address  that is looked up instead of the null
               sender address.
 
        <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a></b>
-              List  of  Postfix features that use <i>domain.tld</i> pat-
-              terns  to  match  <i>sub.domain.tld</i>  (as  opposed   to
+              List of Postfix features that use  <i>domain.tld</i>  pat-
+              terns   to  match  <i>sub.domain.tld</i>  (as  opposed  to
               requiring <i>.domain.tld</i> patterns).
 
        <b><a href="postconf.5.html#transport_maps">transport_maps</a></b>
@@ -258,7 +261,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
        <a href="FILTER_README.html">FILTER_README</a>, external content filter
 
 <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>
diff --git a/postfix/man/junk b/postfix/man/junk
new file mode 100644 (file)
index 0000000..c5f44b8
--- /dev/null
@@ -0,0 +1,2796 @@
+/*++
+/* NAME
+/*     smtpd 8
+/* SUMMARY
+/*     Postfix SMTP server
+/* SYNOPSIS
+/*     \fBsmtpd\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/*     The SMTP server accepts network connection requests
+/*     and performs zero or more SMTP transactions per connection.
+/*     Each received message is piped through the \fBcleanup\fR(8)
+/*     daemon, and is placed into the \fBincoming\fR queue as one
+/*     single queue file.  For this mode of operation, the program
+/*     expects to be run from the \fBmaster\fR(8) process manager.
+/*
+/*     Alternatively, the SMTP server takes an established
+/*     connection on standard input and deposits messages directly
+/*     into the \fBmaildrop\fR queue. In this so-called stand-alone
+/*     mode, the SMTP server can accept mail even while the mail
+/*     system is not running.
+/*
+/*     The SMTP server implements a variety of policies for connection
+/*     requests, and for parameters given to \fBHELO, ETRN, MAIL FROM, VRFY\fR
+/*     and \fBRCPT TO\fR commands. They are detailed below and in the
+/*     \fBmain.cf\fR configuration file.
+/* SECURITY
+/* .ad
+/* .fi
+/*     The SMTP server is moderately security-sensitive. It talks to SMTP
+/*     clients and to DNS servers on the network. The SMTP server can be
+/*     run chrooted at fixed low privilege.
+/* STANDARDS
+/*     RFC 821 (SMTP protocol)
+/*     RFC 1123 (Host requirements)
+/*     RFC 1652 (8bit-MIME transport)
+/*     RFC 1869 (SMTP service extensions)
+/*     RFC 1870 (Message Size Declaration)
+/*     RFC 1985 (ETRN command)
+/*     RFC 2554 (AUTH command)
+/*     RFC 2821 (SMTP protocol)
+/*     RFC 2920 (SMTP Pipelining)
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/*
+/*     Depending on the setting of the \fBnotify_classes\fR parameter,
+/*     the postmaster is notified of bounces, protocol problems,
+/*     policy violations, and of other trouble.
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     Changes to \fBmain.cf\fR are picked up automatically, as smtpd(8)
+/*     processes run for only a limited amount of time. Use the command
+/*     "\fBpostfix reload\fR" to speed up a change.
+/*
+/*     The text below provides only a parameter summary. See
+/*     postconf(5) for more details including examples.
+/* COMPATIBILITY CONTROLS
+/* .ad
+/* .fi
+/*     The following parameters work around implementation errors in other
+/*     software, and/or allow you to override standards in order to prevent
+/*     undesirable use.
+/* .ad
+/* .fi
+/* .IP "\fBbroken_sasl_auth_clients (no)\fR"
+/*     Enable inter-operability with SMTP clients that implement an obsolete
+/*     version of the AUTH command (RFC 2554).
+/* .IP "\fBdisable_vrfy_command (no)\fR"
+/*     Disable the SMTP VRFY command.
+/* .IP "\fBsmtpd_noop_commands (empty)\fR"
+/*     List of commands that the Postfix SMTP server replies to with "250
+/*     Ok", without doing any syntax checks and without changing state.
+/* .IP "\fBstrict_rfc821_envelopes (no)\fR"
+/*     Require that addresses received in SMTP MAIL FROM and RCPT TO
+/*     commands are enclosed with <>, and that those addresses do
+/*     not contain RFC 822 style comments or phrases.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBresolve_null_domain (no)\fR"
+/*     Resolve an address that ends in the "@" null domain as if the
+/*     local hostname were specified, instead of rejecting the address as
+/*     invalid.
+/* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR"
+/*     Request that the Postfix SMTP server rejects mail from unknown
+/*     sender addresses, even when no explicit reject_unlisted_sender
+/*     access restriction is specified.
+/* .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR"
+/*     What SMTP clients Postfix will not offer AUTH support to.
+/* AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS
+/* .ad
+/* .fi
+/*     As of version 1.0, Postfix can be configured to send new mail to
+/*     an external content filter AFTER the mail is queued. This content
+/*     filter is expected to inject mail back into a (Postfix or other)
+/*     MTA for further delivery. See the FILTER_README document for details.
+/* .IP "\fBcontent_filter (empty)\fR"
+/*     The name of a mail delivery transport that filters mail after
+/*     it is queued.
+/* BEFORE QUEUE EXTERNAL CONTENT INSPECTION CONTROLS
+/* .ad
+/* .fi
+/*     As of version 2.1, the Postfix SMTP server can be configured
+/*     to send incoming mail to a real-time SMTP-based content filter
+/*     BEFORE mail is queued.  This content filter is expected to inject
+/*     mail back into Postfix.  See the SMTPD_PROXY_README document for
+/*     details on how to configure and operate this feature.
+/* .IP "\fBsmtpd_proxy_filter (empty)\fR"
+/*     The hostname and TCP port of the mail filtering proxy server.
+/* .IP "\fBsmtpd_proxy_ehlo ($myhostname)\fR"
+/*     How the Postfix SMTP server announces itself to the proxy filter.
+/* .IP "\fBsmtpd_proxy_timeout (100s)\fR"
+/*     The time limit for connecting to a proxy filter and for sending or
+/*     receiving information.
+/* GENERAL CONTENT INSPECTION CONTROLS
+/* .ad
+/* .fi
+/*     The following parameters are applicable for both built-in
+/*     and external content filters.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBreceive_override_options (empty)\fR"
+/*     Enable or disable recipient validation, built-in content
+/*     filtering, or address rewriting.
+/* EXTERNAL CONTENT INSPECTION CONTROLS
+/* .ad
+/* .fi
+/*     The following parameters are applicable for both before-queue
+/*     and after-queue content filtering.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBsmtpd_authorized_xforward_hosts (empty)\fR"
+/*     What SMTP clients are allowed to use the XFORWARD feature.
+/* SASL AUTHENTICATION CONTROLS
+/* .ad
+/* .fi
+/*     Postfix SASL support (RFC 2554) can be used to authenticate remote
+/*     SMTP clients to the Postfix SMTP server, and to authenticate the
+/*     Postfix SMTP client to a remote SMTP server.
+/*     See the SASL_README document for details.
+/* .IP "\fBbroken_sasl_auth_clients (no)\fR"
+/*     Enable inter-operability with SMTP clients that implement an obsolete
+/*     version of the AUTH command (RFC 2554).
+/* .IP "\fBsmtpd_sasl_auth_enable (no)\fR"
+/*     Enable SASL authentication in the Postfix SMTP server.
+/* .IP "\fBsmtpd_sasl_application_name (smtpd)\fR"
+/*     The application name used for SASL server initialization.
+/* .IP "\fBsmtpd_sasl_local_domain (empty)\fR"
+/*     The name of the local SASL authentication realm.
+/* .IP "\fBsmtpd_sasl_security_options (noanonymous)\fR"
+/*     Restrict what authentication mechanisms the Postfix SMTP server
+/*     will offer to the client.
+/* .IP "\fBsmtpd_sender_login_maps (empty)\fR"
+/*     Optional lookup table with the SASL login names that own sender
+/*     (MAIL FROM) addresses.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR"
+/*     What SMTP clients Postfix will not offer AUTH support to.
+/* VERP SUPPORT CONTROLS
+/* .ad
+/* .fi
+/*     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.  The VERP_README file
+/*     describes configuration and operation 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.
+/* .IP "\fBdefault_verp_delimiters (+=)\fR"
+/*     The two default VERP delimiter characters.
+/* .IP "\fBverp_delimiter_filter (-=+)\fR"
+/*     The characters Postfix accepts as VERP delimiter characters on the
+/*     Postfix sendmail(1) command line and in SMTP commands.
+/* .PP
+/*     Available in Postfix version 1.1 and 2.0:
+/* .IP "\fBauthorized_verp_clients ($mynetworks)\fR"
+/*     What SMTP clients are allowed to specify the XVERP command.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBsmtpd_authorized_verp_clients ($authorized_verp_clients)\fR"
+/*     What SMTP clients are allowed to specify the XVERP command.
+/* TROUBLE SHOOTING CONTROLS
+/* .ad
+/* .fi
+/*     The DEBUG_README 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 processes under control of
+/*     a call tracer or debugger.
+/* .IP "\fBdebug_peer_level (2)\fR"
+/*     The increment in verbose logging level when a remote client or
+/*     server matches a pattern in the debug_peer_list parameter.
+/* .IP "\fBdebug_peer_list (empty)\fR"
+/*     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 $debug_peer_level.
+/* .IP "\fBerror_notice_recipient (postmaster)\fR"
+/*     The recipient of postmaster notifications about mail delivery
+/*     problems that are caused by policy, resource, software or protocol
+/*     errors.
+/* .IP "\fBnotify_classes (resource, software)\fR"
+/*     The list of error classes that are reported to the postmaster.
+/* .IP "\fBsoft_bounce (no)\fR"
+/*     Safety net to keep mail queued that would otherwise be returned to
+/*     the sender.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBsmtpd_authorized_xclient_hosts (empty)\fR"
+/*     What SMTP clients are allowed to use the XCLIENT feature.
+/* KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS
+/* .ad
+/* .fi
+/*     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 LOCAL_RECIPIENT_README and ADDRESS_CLASS_README
+/*     documents.
+/* .IP "\fBshow_user_unknown_table_name (yes)\fR"
+/*     Display the name of the recipient table in the "User unknown"
+/*     responses.
+/* .IP "\fBcanonical_maps (empty)\fR"
+/*     Optional address mapping lookup tables for message headers and
+/*     envelopes.
+/* .IP "\fBrecipient_canonical_maps (empty)\fR"
+/*     Optional address mapping lookup tables for envelope and header
+/*     recipient addresses.
+/* .PP
+/*     Parameters concerning known/unknown local recipients:
+/* .IP "\fBmydestination ($myhostname, localhost.$mydomain, localhost)\fR"
+/*     The list of domains that are delivered via the $local_transport
+/*     mail delivery transport.
+/* .IP "\fBinet_interfaces (all)\fR"
+/*     The network interface addresses that this mail system receives mail
+/*     on.
+/* .IP "\fBproxy_interfaces (empty)\fR"
+/*     The network interface addresses that this mail system receives mail
+/*     on by way of a proxy or network address translation unit.
+/* .IP "\fBlocal_recipient_maps (proxy:unix:passwd.byname $alias_maps)\fR"
+/*     Lookup tables with all names or addresses of local recipients:
+/*     a recipient address is local when its domain matches $mydestination,
+/*     $inet_interfaces or $proxy_interfaces.
+/* .IP "\fBunknown_local_recipient_reject_code (550)\fR"
+/*     The numerical Postfix SMTP server response code when a recipient
+/*     address is local, and $local_recipient_maps specifies a list of
+/*     lookup tables that does not match the recipient.
+/* .PP
+/*     Parameters concerning known/unknown recipients of relay destinations:
+/* .IP "\fBrelay_domains ($mydestination)\fR"
+/*     What destination domains (and subdomains thereof) this system
+/*     will relay mail to.
+/* .IP "\fBrelay_recipient_maps (empty)\fR"
+/*     Optional lookup tables with all valid addresses in the domains
+/*     that match $relay_domains.
+/* .IP "\fBunknown_relay_recipient_reject_code (550)\fR"
+/*     The numerical Postfix SMTP server reply code when a recipient
+/*     address matches $relay_domains, and relay_recipient_maps specifies
+/*     a list of lookup tables that does not match the recipient address.
+/* .PP
+/*     Parameters concerning known/unknown recipients in virtual alias
+/*     domains:
+/* .IP "\fBvirtual_alias_domains ($virtual_alias_maps)\fR"
+/*     Optional list of names of virtual alias domains, that is,
+/*     domains for which all addresses are aliased to addresses in other
+/*     local or remote domains.
+/* .IP "\fBvirtual_alias_maps ($virtual_maps)\fR"
+/*     Optional lookup tables that alias specific mail addresses or domains
+/*     to other local or remote address.
+/* .IP "\fBunknown_virtual_alias_reject_code (550)\fR"
+/*     The SMTP server reply code when a recipient address matches
+/*     $virtual_alias_domains, and $virtual_alias_maps specifies a list
+/*     of lookup tables that does not match the recipient address.
+/* .PP
+/*     Parameters concerning known/unknown recipients in virtual mailbox
+/*     domains:
+/* .IP "\fBvirtual_mailbox_domains ($virtual_mailbox_maps)\fR"
+/*     The list of domains that are delivered via the $virtual_transport
+/*     mail delivery transport.
+/* .IP "\fBvirtual_mailbox_maps (empty)\fR"
+/*     Optional lookup tables with all valid addresses in the domains that
+/*     match $virtual_mailbox_domains.
+/* .IP "\fBunknown_virtual_mailbox_reject_code (550)\fR"
+/*     The SMTP server reply code when a recipient address matches
+/*     $virtual_mailbox_domains, and $virtual_mailbox_maps specifies a list
+/*     of lookup tables that does not match the recipient address.
+/* RESOURCE AND RATE CONTROLS
+/* .ad
+/* .fi
+/*     The following parameters limit resource usage by the SMTP
+/*     server and/or control client request rates.
+/* .IP "\fBline_length_limit (2048)\fR"
+/*     Upon input, long lines are chopped up into pieces of at most
+/*     this length; upon delivery, long lines are reconstructed.
+/* .IP "\fBqueue_minfree (0)\fR"
+/*     The minimal amount of free space in bytes in the queue file system
+/*     that is needed to receive mail.
+/* .IP "\fBmessage_size_limit (10240000)\fR"
+/*     The maximal size in bytes of a message, including envelope information.
+/* .IP "\fBsmtpd_recipient_limit (1000)\fR"
+/*     The maximal number of recipients that the Postfix SMTP server
+/*     accepts per message delivery request.
+/* .IP "\fBsmtpd_timeout (300s)\fR"
+/*     The time limit for sending a Postfix SMTP server response and for
+/*     receiving a remote SMTP client request.
+/* .IP "\fBsmtpd_history_flush_threshold (100)\fR"
+/*     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.
+/* .PP
+/*     Not available in Postfix version 2.1:
+/* .IP "\fBsmtpd_client_connection_count_limit (50)\fR"
+/*     How many simultaneous connections any SMTP client is allowed to
+/*     make to the SMTP service.
+/* .IP "\fBsmtpd_client_connection_rate_limit (0)\fR"
+/*     The maximal number of connection attempts any client is allowed to
+/*     make to this service per time unit.
+/* .IP "\fBsmtpd_client_connection_limit_exceptions ($mynetworks)\fR"
+/*     Clients that are excluded from connection count or connection rate
+/*     restrictions.
+/* TARPIT CONTROLS
+/* .ad
+/* .fi
+/*     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 controlled by an error counter
+/*     that counts the number of errors within an SMTP session that a
+/*     client makes without delivering mail.
+/* .IP "\fBsmtpd_error_sleep_time (1s)\fR"
+/*     With Postfix 2.1 and later: the SMTP server response delay after
+/*     a client has made more than $smtpd_soft_error_limit errors, and
+/*     fewer than $smtpd_hard_error_limit errors, without delivering mail.
+/* .IP "\fBsmtpd_soft_error_limit (10)\fR"
+/*     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.
+/* .IP "\fBsmtpd_hard_error_limit (20)\fR"
+/*     The maximal number of errors a remote SMTP client is allowed to
+/*     make without delivering mail.
+/* .IP "\fBsmtpd_junk_command_limit (100)\fR"
+/*     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 counter with each junk command.
+/* .IP "\fBsmtpd_recipient_overshoot_limit (1000)\fR"
+/*     The number of recipients that a remote SMTP client can send in
+/*     excess of the limit specified with $smtpd_recipient_limit, before
+/*     the Postfix SMTP server increments the per-session error count
+/*     for each excess recipient.
+/* ACCESS POLICY DELEGATION CONTROLS
+/* .ad
+/* .fi
+/*     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 SMTPD_POLICY_README for more information.
+/* .IP "\fBsmtpd_policy_service_timeout (100s)\fR"
+/*     The time limit for connecting to, writing to or receiving from a
+/*     delegated SMTPD policy server.
+/* .IP "\fBsmtpd_policy_service_max_idle (300s)\fR"
+/*     The time after which an idle SMTPD policy service connection is
+/*     closed.
+/* .IP "\fBsmtpd_policy_service_max_ttl (1000s)\fR"
+/*     The time after which an active SMTPD policy service connection is
+/*     closed.
+/* .IP "\fBsmtpd_policy_service_timeout (100s)\fR"
+/*     The time limit for connecting to, writing to or receiving from a
+/*     delegated SMTPD policy server.
+/* ACCESS CONTROLS
+/* .ad
+/* .fi
+/*     The SMTPD_ACCESS_README document gives an introduction to all the
+/*     SMTP server access control features.
+/* .IP "\fBsmtpd_delay_reject (yes)\fR"
+/*     Wait until the RCPT TO command before evaluating
+/*     $smtpd_client_restrictions, $smtpd_helo_restrictions and
+/*     $smtpd_sender_restrictions, or wait until the ETRN command before
+/*     evaluating $smtpd_client_restrictions and $smtpd_helo_restrictions.
+/* .IP "\fBparent_domain_matches_subdomains (see 'postconf -d' output)\fR"
+/*     What Postfix features match subdomains of "domain.tld" automatically,
+/*     instead of requiring an explicit ".domain.tld" pattern.
+/* .IP "\fBsmtpd_client_restrictions (empty)\fR"
+/*     Optional SMTP server access restrictions in the context of a client
+/*     SMTP connection request.
+/* .IP "\fBsmtpd_helo_required (no)\fR"
+/*     Require that a remote SMTP client introduces itself at the beginning
+/*     of an SMTP session with the HELO or EHLO command.
+/* .IP "\fBsmtpd_helo_restrictions (empty)\fR"
+/*     Optional restrictions that the Postfix SMTP server applies in the
+/*     context of the SMTP HELO command.
+/* .IP "\fBsmtpd_sender_restrictions (empty)\fR"
+/*     Optional restrictions that the Postfix SMTP server applies in the
+/*     context of the MAIL FROM command.
+/* .IP "\fBsmtpd_recipient_restrictions (permit_mynetworks, reject_unauth_destination)\fR"
+/*     The access restrictions that the Postfix SMTP server applies in
+/*     the context of the RCPT TO command.
+/* .IP "\fBsmtpd_etrn_restrictions (empty)\fR"
+/*     Optional SMTP server access restrictions in the context of a client
+/*     ETRN request.
+/* .IP "\fBallow_untrusted_routing (no)\fR"
+/*     Forward mail with sender-specified routing (user[@%!]remote[@%!]site)
+/*     from untrusted clients to destinations matching $relay_domains.
+/* .IP "\fBsmtpd_restriction_classes (empty)\fR"
+/*     User-defined aliases for groups of access restrictions.
+/* .IP "\fBsmtpd_null_access_lookup_key (<>)\fR"
+/*     The lookup key to be used in SMTP access(5) tables instead of the
+/*     null sender address.
+/* .IP "\fBpermit_mx_backup_networks (empty)\fR"
+/*     Restrict the use of the permit_mx_backup SMTP access feature to
+/*     only domains whose primary MX hosts match the listed networks.
+/* .PP
+/*     Available in Postfix version 2.0 and later:
+/* .IP "\fBsmtpd_data_restrictions (empty)\fR"
+/*     Optional access restrictions that the Postfix SMTP server applies
+/*     in the context of the SMTP DATA command.
+/* .IP "\fBsmtpd_expansion_filter (see 'postconf -d' output)\fR"
+/*     What characters are allowed in $name expansions of RBL reply
+/*     templates.
+/* .PP
+/*     Available in Postfix version 2.1 and later:
+/* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR"
+/*     Request that the Postfix SMTP server rejects mail from unknown
+/*     sender addresses, even when no explicit reject_unlisted_sender
+/*     access restriction is specified.
+/* .IP "\fBsmtpd_reject_unlisted_recipient (yes)\fR"
+/*     Request that the Postfix SMTP server rejects mail for unknown
+/*     recipient addresses, even when no explicit reject_unlisted_recipient
+/*     access restriction is specified.
+/* SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS
+/* .ad
+/* .fi
+/*     Postfix version 2.1 introduces sender and address verification.
+/*     This feature is implemented by sending probe email messages that
+/*     are not actually delivered.
+/*     This feature is requested via the reject_unverified_sender and
+/*     reject_unverified_recipient access restrictions.  The status of
+/*     verification probes is maintained by the verify(8) server.
+/*     See the file ADDRESS_VERIFICATION_README for information
+/*     about how to configure and operate the Postfix sender/recipient
+/*     address verification service.
+/* .IP "\fBaddress_verify_poll_count (3)\fR"
+/*     How many times to query the verify(8) service for the completion
+/*     of an address verification request in progress.
+/* .IP "\fBaddress_verify_poll_delay (3s)\fR"
+/*     The delay between queries for the completion of an address
+/*     verification request in progress.
+/* .IP "\fBaddress_verify_sender (postmaster)\fR"
+/*     The sender address to use in address verification probes.
+/* .IP "\fBunverified_sender_reject_code (450)\fR"
+/*     The numerical Postfix SMTP server response code when a recipient
+/*     address is rejected by the reject_unverified_sender restriction.
+/* .IP "\fBunverified_recipient_reject_code (450)\fR"
+/*     The numerical Postfix SMTP server response when a recipient address
+/*     is rejected by the reject_unverified_recipient restriction.
+/* ACCESS CONTROL RESPONSES
+/* .ad
+/* .fi
+/*     The following parameters control numerical SMTP reply codes
+/*     and/or text responses.
+/* .IP "\fBaccess_map_reject_code (554)\fR"
+/*     The numerical Postfix SMTP server response code when a client
+/*     is rejected by an access(5) map restriction.
+/* .IP "\fBdefer_code (450)\fR"
+/*     The numerical Postfix SMTP server response code when a remote SMTP
+/*     client request is rejected by the "defer" restriction.
+/* .IP "\fBinvalid_hostname_reject_code (501)\fR"
+/*     The numerical Postfix SMTP server response code when the client
+/*     HELO or EHLO command parameter is rejected by the reject_invalid_hostname
+/*     restriction.
+/* .IP "\fBmaps_rbl_reject_code (554)\fR"
+/*     The numerical Postfix SMTP server response code when a remote SMTP
+/*     client request is blocked by the reject_rbl_client, reject_rhsbl_client,
+/*     reject_rhsbl_sender or reject_rhsbl_recipient restriction.
+/* .IP "\fBnon_fqdn_reject_code (504)\fR"
+/*     The numerical Postfix SMTP server reply code when a client request
+/*     is rejected by the reject_non_fqdn_hostname, reject_non_fqdn_sender
+/*     or reject_non_fqdn_recipient restriction.
+/* .IP "\fBreject_code (554)\fR"
+/*     The numerical Postfix SMTP server response code when a remote SMTP
+/*     client request is rejected by the "\fBreject\fR" restriction.
+/* .IP "\fBrelay_domains_reject_code (554)\fR"
+/*     The numerical Postfix SMTP server response code when a client
+/*     request is rejected by the reject_unauth_destination recipient
+/*     restriction.
+/* .IP "\fBunknown_address_reject_code (450)\fR"
+/*     The numerical Postfix SMTP server response code when a sender or
+/*     recipient address is rejected by the reject_unknown_sender_domain
+/*     or reject_unknown_recipient_domain restriction.
+/* .IP "\fBunknown_client_reject_code (450)\fR"
+/*     The numerical Postfix SMTP server response code when a client
+/*     without valid address <=> name mapping is rejected by the
+/*     reject_unknown_client restriction.
+/* .IP "\fBunknown_hostname_reject_code (450)\fR"
+/*     The numerical Postfix SMTP server response code when the hostname
+/*     specified with the HELO or EHLO command is rejected by the
+/*     reject_unknown_hostname restriction.
+/* .PP
+/*     Available in Postfix version 2.0 and later:
+/* .IP "\fBdefault_rbl_reply (see 'postconf -d' output)\fR"
+/*     The default SMTP server response template for a request that is
+/*     rejected by an RBL-based restriction.
+/* .IP "\fBmulti_recipient_bounce_reject_code (550)\fR"
+/*     The numerical Postfix SMTP server response code when a remote SMTP
+/*     client request is blocked by the reject_multi_recipient_bounce
+/*     restriction.
+/* .IP "\fBrbl_reply_maps (empty)\fR"
+/*     Optional lookup tables with RBL response templates.
+/* MISCELLANEOUS CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+/*     The default location of the Postfix main.cf and master.cf
+/*     configuration files.
+/* .IP "\fBdaemon_timeout (18000s)\fR"
+/*     How much time a Postfix daemon process may take to handle a
+/*     request before it is terminated by a built-in watchdog timer.
+/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
+/*     The location of all postfix administrative commands.
+/* .IP "\fBdouble_bounce_sender (double-bounce)\fR"
+/*     The sender address of postmaster notifications that are generated
+/*     by the mail system.
+/* .IP "\fBipc_timeout (3600s)\fR"
+/*     The time limit for sending or receiving information over an internal
+/*     communication channel.
+/* .IP "\fBmail_name (Postfix)\fR"
+/*     The mail system name that is displayed in Received: headers, in
+/*     the SMTP greeting banner, and in bounced mail.
+/* .IP "\fBmail_owner (postfix)\fR"
+/*     The UNIX system account that owns the Postfix queue and most Postfix
+/*     daemon processes.
+/* .IP "\fBmax_idle (100s)\fR"
+/*     The maximum amount of time that an idle Postfix daemon process
+/*     waits for the next service request before exiting.
+/* .IP "\fBmax_use (100)\fR"
+/*     The maximal number of connection requests before a Postfix daemon
+/*     process terminates.
+/* .IP "\fBmyhostname (see 'postconf -d' output)\fR"
+/*     The internet hostname of this mail system.
+/* .IP "\fBmynetworks (see 'postconf -d' output)\fR"
+/*     The list of "trusted" SMTP clients that have more privileges than
+/*     "strangers".
+/* .IP "\fBmyorigin ($myhostname)\fR"
+/*     The default domain name that locally-posted mail appears to come
+/*     from, and that locally posted mail is delivered to.
+/* .IP "\fBprocess_id (read-only)\fR"
+/*     The process ID of a Postfix command or daemon process.
+/* .IP "\fBprocess_name (read-only)\fR"
+/*     The process name of a Postfix command or daemon process.
+/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
+/*     The location of the Postfix top-level queue directory.
+/* .IP "\fBrecipient_delimiter (empty)\fR"
+/*     The separator between user names and address extensions (user+foo).
+/* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
+/*     The text that follows the 220 status code in the SMTP greeting
+/*     banner.
+/* .IP "\fBsyslog_facility (mail)\fR"
+/*     The syslog facility of Postfix logging.
+/* .IP "\fBsyslog_name (postfix)\fR"
+/*     The mail system name that is prepended to the process name in syslog
+/*     records, so that "smtpd" becomes, for example, "postfix/smtpd".
+/* SEE ALSO
+/*     cleanup(8), message canonicalization
+/*     trivial-rewrite(8), address resolver
+/*     verify(8), address verification service
+/*     postconf(5), configuration parameters
+/*     master(8), process manager
+/*     syslogd(8), system logging
+/* README FILES
+/* .ad
+/* .fi
+/*     Use "\fBpostconf readme_directory\fR" or
+/*     "\fBpostconf html_directory\fR" to locate this information.
+/* .na
+/* .nf
+/*     ADDRESS_CLASS_README, blocking unknown hosted or relay recipients
+/*     FILTER_README, external after-queue content filter
+/*     LOCAL_RECIPIENT_README, blocking unknown local recipients
+/*     SMTPD_ACCESS_README, built-in access policies
+/*     SMTPD_POLICY_README, external policy server
+/*     SMTPD_PROXY_README, external before-queue content filter
+/*     SASL_README, Postfix SASL howto
+/*     VERP_README, Postfix XVERP extension
+/*     XCLIENT_README, Postfix XCLIENT extension
+/*     XFORWARD_README, Postfix XFORWARD extension
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>                     /* remove() */
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+#include <stddef.h>                    /* offsetof() */
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+#include <events.h>
+#include <smtp_stream.h>
+#include <valid_hostname.h>
+#include <dict.h>
+#include <watchdog.h>
+#include <iostuff.h>
+#include <split_at.h>
+#include <name_code.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <record.h>
+#include <rec_type.h>
+#include <mail_proto.h>
+#include <cleanup_user.h>
+#include <mail_date.h>
+#include <mail_conf.h>
+#include <off_cvt.h>
+#include <debug_peer.h>
+#include <mail_error.h>
+#include <flush_clnt.h>
+#include <mail_stream.h>
+#include <mail_queue.h>
+#include <tok822.h>
+#include <verp_sender.h>
+#include <string_list.h>
+#include <quote_822_local.h>
+#include <lex_822.h>
+#include <namadr_list.h>
+#include <input_transp.h>
+#ifdef SNAPSHOT
+#include <anvil_clnt.h>
+#endif
+#include <flush_clnt.h>
+
+/* Single-threaded server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific */
+
+#include <smtpd_token.h>
+#include <smtpd.h>
+#include <smtpd_check.h>
+#include <smtpd_chat.h>
+#include <smtpd_sasl_proto.h>
+#include <smtpd_sasl_glue.h>
+#include <smtpd_proxy.h>
+
+ /*
+  * Tunable parameters. Make sure that there is some bound on the length of
+  * an SMTP command, so that the mail system stays in control even when a
+  * malicious client sends commands of unreasonable length (qmail-dos-1).
+  * Make sure there is some bound on the number of recipients, so that the
+  * mail system stays in control even when a malicious client sends an
+  * unreasonable number of recipients (qmail-dos-2).
+  */
+int     var_smtpd_rcpt_limit;
+int     var_smtpd_tmout;
+int     var_smtpd_soft_erlim;
+int     var_smtpd_hard_erlim;
+int     var_queue_minfree;             /* XXX use off_t */
+char   *var_smtpd_banner;
+char   *var_notify_classes;
+char   *var_client_checks;
+char   *var_helo_checks;
+char   *var_mail_checks;
+char   *var_rcpt_checks;
+char   *var_etrn_checks;
+char   *var_data_checks;
+int     var_unk_client_code;
+int     var_bad_name_code;
+int     var_unk_name_code;
+int     var_unk_addr_code;
+int     var_relay_code;
+int     var_maps_rbl_code;
+int     var_access_map_code;
+char   *var_maps_rbl_domains;
+char   *var_rbl_reply_maps;
+int     var_helo_required;
+int     var_reject_code;
+int     var_defer_code;
+int     var_smtpd_err_sleep;
+int     var_non_fqdn_code;
+char   *var_error_rcpt;
+int     var_smtpd_delay_reject;
+char   *var_rest_classes;
+int     var_strict_rfc821_env;
+bool    var_disable_vrfy_cmd;
+char   *var_canonical_maps;
+char   *var_rcpt_canon_maps;
+char   *var_virt_alias_maps;
+char   *var_virt_mailbox_maps;
+char   *var_alias_maps;
+char   *var_local_rcpt_maps;
+bool    var_allow_untrust_route;
+int     var_smtpd_junk_cmd_limit;
+int     var_smtpd_rcpt_overlim;
+bool    var_smtpd_sasl_enable;
+char   *var_smtpd_sasl_opts;
+char   *var_smtpd_sasl_appname;
+char   *var_smtpd_sasl_realm;
+char   *var_smtpd_sasl_exceptions_networks;
+char   *var_filter_xport;
+bool    var_broken_auth_clients;
+char   *var_perm_mx_networks;
+char   *var_smtpd_snd_auth_maps;
+char   *var_smtpd_noop_cmds;
+char   *var_smtpd_null_key;
+int     var_smtpd_hist_thrsh;
+char   *var_smtpd_exp_filter;
+char   *var_def_rbl_reply;
+int     var_unv_from_code;
+int     var_unv_rcpt_code;
+int     var_mul_rcpt_code;
+char   *var_relay_rcpt_maps;
+char   *var_verify_sender;
+int     var_local_rcpt_code;
+int     var_virt_alias_code;
+int     var_virt_mailbox_code;
+int     var_relay_rcpt_code;
+char   *var_verp_clients;
+int     var_show_unk_rcpt_table;
+int     var_verify_poll_count;
+int     var_verify_poll_delay;
+char   *var_smtpd_proxy_filt;
+int     var_smtpd_proxy_tmout;
+char   *var_smtpd_proxy_ehlo;
+char   *var_input_transp;
+int     var_smtpd_policy_tmout;
+int     var_smtpd_policy_idle;
+int     var_smtpd_policy_ttl;
+char   *var_xclient_hosts;
+char   *var_xforward_hosts;
+bool    var_smtpd_rej_unl_from;
+bool    var_smtpd_rej_unl_rcpt;
+
+#ifdef SNAPSHOT
+int     var_smtpd_crate_limit;
+int     var_smtpd_cconn_limit;
+char   *var_smtpd_hoggers;
+
+#endif
+
+ /*
+  * Silly little macros.
+  */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+ /*
+  * VERP command name.
+  */
+#define VERP_CMD       "XVERP"
+#define VERP_CMD_LEN   5
+
+static NAMADR_LIST *verp_clients;
+
+ /*
+  * XCLIENT command. Access control is cached, so that XCLIENT can't override
+  * its own access control.
+  */
+static NAMADR_LIST *xclient_hosts;
+static int xclient_allowed;
+
+ /*
+  * XFORWARD command. Access control is cached.
+  */
+static NAMADR_LIST *xforward_hosts;
+static int xforward_allowed;
+
+ /*
+  * Client connection and rate limiting.
+  */
+#ifdef SNAPSHOT
+ANVIL_CLNT *anvil_clnt;
+static NAMADR_LIST *hogger_list;
+
+#endif
+
+ /*
+  * Other application-specific globals.
+  */
+int     smtpd_input_transp_mask;
+
+ /*
+  * Forward declarations.
+  */
+static void helo_reset(SMTPD_STATE *);
+static void mail_reset(SMTPD_STATE *);
+static void rcpt_reset(SMTPD_STATE *);
+static void chat_reset(SMTPD_STATE *, int);
+
+#ifdef USE_SASL_AUTH
+
+ /*
+  * SASL exceptions.
+  */
+static NAMADR_LIST *sasl_exceptions_networks;
+
+/* sasl_client_exception - can we offer AUTH for this client */
+
+static int sasl_client_exception(SMTPD_STATE *state)
+{
+    int     match;
+
+    /*
+     * This is to work around a Netscape mail client bug where it tries to
+     * use AUTH if available, even if user has not configured it. Returns
+     * TRUE if AUTH should be offered in the EHLO.
+     */
+    if (sasl_exceptions_networks == 0)
+       return (0);
+
+    match = namadr_list_match(sasl_exceptions_networks,
+                             state->name, state->addr);
+
+    if (msg_verbose)
+       msg_info("sasl_exceptions: %s[%s], match=%d",
+                state->name, state->addr, match);
+
+    return (match);
+}
+
+#endif
+
+/* collapse_args - put arguments together again */
+
+static void collapse_args(int argc, SMTPD_TOKEN *argv)
+{
+    int     i;
+
+    for (i = 1; i < argc; i++) {
+       vstring_strcat(argv[0].vstrval, " ");
+       vstring_strcat(argv[0].vstrval, argv[i].strval);
+    }
+    argv[0].strval = STR(argv[0].vstrval);
+}
+
+/* helo_cmd - process HELO command */
+
+static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err;
+
+    if (argc < 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: HELO hostname");
+       return (-1);
+    }
+    if (argc > 2)
+       collapse_args(argc - 1, argv + 1);
+    if (SMTPD_STAND_ALONE(state) == 0
+       && var_smtpd_delay_reject == 0
+       && (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    if (state->helo_name != 0)
+       helo_reset(state);
+    chat_reset(state, var_smtpd_hist_thrsh);
+    mail_reset(state);
+    rcpt_reset(state);
+    state->helo_name = mystrdup(printable(argv[1].strval, '?'));
+    neuter(state->helo_name, "<>()\\\";:@", '?');
+    /* Downgrading the protocol name breaks the unauthorized pipelining test. */
+    if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
+       && strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) {
+       myfree(state->protocol);
+       state->protocol = mystrdup(MAIL_PROTO_SMTP);
+    }
+    smtpd_chat_reply(state, "250 %s", var_myhostname);
+    return (0);
+}
+
+/* ehlo_cmd - process EHLO command */
+
+static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err;
+
+    /*
+     * XXX 2821 new feature: Section 4.1.4 specifies that a server must clear
+     * all buffers and reset the state exactly as if a RSET command had been
+     * issued.
+     */
+    if (argc < 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
+       return (-1);
+    }
+    if (argc > 2)
+       collapse_args(argc - 1, argv + 1);
+    if (SMTPD_STAND_ALONE(state) == 0
+       && var_smtpd_delay_reject == 0
+       && (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    if (state->helo_name != 0)
+       helo_reset(state);
+    chat_reset(state, var_smtpd_hist_thrsh);
+    mail_reset(state);
+    rcpt_reset(state);
+    state->helo_name = mystrdup(printable(argv[1].strval, '?'));
+    neuter(state->helo_name, "<>()\\\";:@", '?');
+    if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0) {
+       myfree(state->protocol);
+       state->protocol = mystrdup(MAIL_PROTO_ESMTP);
+    }
+    smtpd_chat_reply(state, "250-%s", var_myhostname);
+    smtpd_chat_reply(state, "250-PIPELINING");
+    if (var_message_limit)
+       smtpd_chat_reply(state, "250-SIZE %lu",
+                        (unsigned long) var_message_limit);    /* XXX */
+    else
+       smtpd_chat_reply(state, "250-SIZE");
+    if (var_disable_vrfy_cmd == 0)
+       smtpd_chat_reply(state, "250-VRFY");
+    smtpd_chat_reply(state, "250-ETRN");
+#ifdef USE_SASL_AUTH
+    if (var_smtpd_sasl_enable && !sasl_client_exception(state)) {
+       smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
+       if (var_broken_auth_clients)
+           smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
+    }
+#endif
+    if (namadr_list_match(verp_clients, state->name, state->addr))
+       smtpd_chat_reply(state, "250-%s", VERP_CMD);
+    /* XCLIENT must not override its own access control. */
+    if (xclient_allowed)
+       smtpd_chat_reply(state, "250-" XCLIENT_CMD
+                        " " XCLIENT_NAME " " XCLIENT_ADDR
+                        " " XCLIENT_PROTO " " XCLIENT_HELO);
+    if (xforward_allowed)
+       smtpd_chat_reply(state, "250-" XFORWARD_CMD
+                        " " XFORWARD_NAME " " XFORWARD_ADDR
+                        " " XFORWARD_PROTO " " XFORWARD_HELO);
+    smtpd_chat_reply(state, "250 8BITMIME");
+    return (0);
+}
+
+/* helo_reset - reset HELO/EHLO command stuff */
+
+static void helo_reset(SMTPD_STATE *state)
+{
+    if (state->helo_name)
+       myfree(state->helo_name);
+    state->helo_name = 0;
+}
+
+/* mail_open_stream - open mail queue file or IPC stream */
+
+static void mail_open_stream(SMTPD_STATE *state)
+{
+    char   *postdrop_command;
+    int     cleanup_flags;
+
+    /*
+     * XXX 2821: An SMTP server is not allowed to "clean up" mail except in
+     * the case of original submissions. Presently, Postfix always runs all
+     * mail through the cleanup server.
+     * 
+     * We could approximate the RFC as follows: Postfix rewrites mail if it
+     * comes from a source that we are willing to relay for. This way, we
+     * avoid rewriting most mail that comes from elsewhere. However, that
+     * requires moving functionality away from the cleanup daemon elsewhere,
+     * such as virtual address expansion, and header/body pattern matching.
+     */
+
+    /*
+     * If running from the master or from inetd, connect to the cleanup
+     * service.
+     */
+    cleanup_flags = CLEANUP_FLAG_MASK_EXTERNAL;
+    if (smtpd_input_transp_mask & INPUT_TRANSP_ADDRESS_MAPPING)
+       cleanup_flags &= ~(CLEANUP_FLAG_BCC_OK | CLEANUP_FLAG_MAP_OK);
+    if (smtpd_input_transp_mask & INPUT_TRANSP_HEADER_BODY)
+       cleanup_flags &= ~CLEANUP_FLAG_FILTER;
+
+    if (SMTPD_STAND_ALONE(state) == 0) {
+       state->dest = mail_stream_service(MAIL_CLASS_PUBLIC,
+                                         var_cleanup_service);
+       if (state->dest == 0
+           || attr_print(state->dest->stream, ATTR_FLAG_NONE,
+                         ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
+                         ATTR_TYPE_END) != 0)
+           msg_fatal("unable to connect to the %s %s service",
+                     MAIL_CLASS_PUBLIC, var_cleanup_service);
+    }
+
+    /*
+     * Otherwise, pipe the message through the privileged postdrop helper.
+     * XXX Make postdrop a manifest constant.
+     */
+    else {
+       postdrop_command = concatenate(var_command_dir, "/postdrop",
+                             msg_verbose ? " -v" : (char *) 0, (char *) 0);
+       state->dest = mail_stream_command(postdrop_command);
+       if (state->dest == 0)
+           msg_fatal("unable to execute %s", postdrop_command);
+       myfree(postdrop_command);
+    }
+    state->cleanup = state->dest->stream;
+    state->queue_id = mystrdup(state->dest->id);
+
+    /*
+     * Record the time of arrival, the sender envelope address, some session
+     * information, and some additional attributes.
+     */
+    if (SMTPD_STAND_ALONE(state) == 0) {
+       rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", state->time);
+       if (*var_filter_xport)
+           rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
+    }
+    rec_fputs(state->cleanup, REC_TYPE_FROM, state->sender);
+    if (state->encoding != 0)
+       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                   MAIL_ATTR_ENCODING, state->encoding);
+
+    /*
+     * Store the client attributes for logging purposes.
+     */
+    if (SMTPD_STAND_ALONE(state) == 0) {
+       if (IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state)))
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
+       if (IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state)))
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
+       if (IS_AVAIL_CLIENT_NAMADDR(FORWARD_NAMADDR(state)))
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
+       if (IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state)))
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_HELO_NAME, FORWARD_HELO(state));
+       if (IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state)))
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
+    }
+    if (state->verp_delims)
+       rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims);
+}
+
+/* extract_addr - extract address from rubble */
+
+static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
+                                 int allow_empty_addr, int strict_rfc821)
+{
+    char   *myname = "extract_addr";
+    TOK822 *tree;
+    TOK822 *tp;
+    TOK822 *addr = 0;
+    int     naddr;
+    int     non_addr;
+    char   *err = 0;
+    char   *junk = 0;
+    char   *text;
+    char   *colon;
+
+    /*
+     * Special case.
+     */
+#define PERMIT_EMPTY_ADDR      1
+#define REJECT_EMPTY_ADDR      0
+
+    /*
+     * Some mailers send RFC822-style address forms (with comments and such)
+     * in SMTP envelopes. We cannot blame users for this: the blame is with
+     * programmers violating the RFC, and with sendmail for being permissive.
+     * 
+     * XXX The SMTP command tokenizer must leave the address in externalized
+     * (quoted) form, so that the address parser can correctly extract the
+     * address from surrounding junk.
+     * 
+     * XXX We have only one address parser, written according to the rules of
+     * RFC 822. That standard differs subtly from RFC 821.
+     */
+    if (msg_verbose)
+       msg_info("%s: input: %s", myname, STR(arg->vstrval));
+    if (STR(arg->vstrval)[0] == '<'
+       && STR(arg->vstrval)[LEN(arg->vstrval) - 1] == '>') {
+       junk = text = mystrndup(STR(arg->vstrval) + 1, LEN(arg->vstrval) - 2);
+    } else
+       text = STR(arg->vstrval);
+
+    /*
+     * Truncate deprecated route address form.
+     */
+    if (*text == '@' && (colon = strchr(text, ':')) != 0)
+       text = colon + 1;
+    tree = tok822_parse(text);
+
+    if (junk)
+       myfree(junk);
+
+    /*
+     * Find trouble.
+     */
+    for (naddr = non_addr = 0, tp = tree; tp != 0; tp = tp->next) {
+       if (tp->type == TOK822_ADDR) {
+           addr = tp;
+           naddr += 1;                         /* count address forms */
+       } else if (tp->type == '<' || tp->type == '>') {
+            /* void */ ;                       /* ignore brackets */
+       } else {
+           non_addr += 1;                      /* count non-address forms */
+       }
+    }
+
+    /*
+     * Report trouble. Log a warning only if we are going to sleep+reject so
+     * that attackers can't flood our logfiles.
+     */
+    if (naddr > 1
+       || (strict_rfc821 && (non_addr || *STR(arg->vstrval) != '<'))) {
+       msg_warn("Illegal address syntax from %s in %s command: %s",
+                state->namaddr, state->where, STR(arg->vstrval));
+       err = "501 Bad address syntax";
+    }
+
+    /*
+     * Overwrite the input with the extracted address. This seems bad design,
+     * but we really are not going to use the original data anymore. What we
+     * start with is quoted (external) form, and what we need is unquoted
+     * (internal form).
+     */
+    if (addr)
+       tok822_internalize(arg->vstrval, addr->head, TOK822_STR_DEFL);
+    else
+       vstring_strcpy(arg->vstrval, "");
+    arg->strval = STR(arg->vstrval);
+
+    /*
+     * Report trouble. Log a warning only if we are going to sleep+reject so
+     * that attackers can't flood our logfiles.
+     */
+    if (err == 0)
+       if ((arg->strval[0] == 0 && !allow_empty_addr)
+           || (strict_rfc821 && arg->strval[0] == '@')
+           || (SMTPD_STAND_ALONE(state) == 0
+               && smtpd_check_addr(STR(arg->vstrval)) != 0)) {
+           msg_warn("Illegal address syntax from %s in %s command: %s",
+                    state->namaddr, state->where, STR(arg->vstrval));
+           err = "501 Bad address syntax";
+       }
+
+    /*
+     * Cleanup.
+     */
+    tok822_free_tree(tree);
+    if (msg_verbose)
+       msg_info("%s: result: %s", myname, STR(arg->vstrval));
+    return (err);
+}
+
+/* mail_cmd - process MAIL command */
+
+static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err;
+    int     narg;
+    char   *arg;
+    char   *verp_delims = 0;
+
+    state->encoding = 0;
+
+    /*
+     * Sanity checks.
+     * 
+     * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
+     * command in which invalid character codes have been employed, and for
+     * which there are no other reasons for rejection, MUST reject that
+     * command with a 501 response. So much for the principle of "be liberal
+     * in what you accept, be strict in what you send".
+     */
+    if (var_helo_required && state->helo_name == 0) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       smtpd_chat_reply(state, "503 Error: send HELO/EHLO first");
+       return (-1);
+    }
+#define IN_MAIL_TRANSACTION(state) ((state)->sender != 0)
+
+    if (IN_MAIL_TRANSACTION(state)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "503 Error: nested MAIL command");
+       return (-1);
+    }
+    if (argc < 3
+       || strcasecmp(argv[1].strval, "from:") != 0) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: MAIL FROM: <address>");
+       return (-1);
+    }
+    if (argv[2].tokval == SMTPD_TOK_ERROR) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Bad sender address syntax");
+       return (-1);
+    }
+    if ((err = extract_addr(state, argv + 2, PERMIT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    for (narg = 3; narg < argc; narg++) {
+       arg = argv[narg].strval;
+       if (strcasecmp(arg, "BODY=8BITMIME") == 0) {    /* RFC 1652 */
+           state->encoding = MAIL_ATTR_ENC_8BIT;
+       } else if (strcasecmp(arg, "BODY=7BIT") == 0) { /* RFC 1652 */
+           state->encoding = MAIL_ATTR_ENC_7BIT;
+       } else if (strncasecmp(arg, "SIZE=", 5) == 0) { /* RFC 1870 */
+           /* Reject non-numeric size. */
+           if (!alldig(arg + 5)) {
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               smtpd_chat_reply(state, "501 Bad message size syntax");
+               return (-1);
+           }
+           /* Reject size overflow. */
+           if ((state->msg_size = off_cvt_string(arg + 5)) < 0) {
+               smtpd_chat_reply(state, "552 Message size exceeds file system imposed limit");
+               state->error_mask |= MAIL_ERROR_POLICY;
+               return (-1);
+           }
+#ifdef USE_SASL_AUTH
+       } else if (var_smtpd_sasl_enable && strncasecmp(arg, "AUTH=", 5) == 0) {
+           if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) {
+               smtpd_chat_reply(state, "%s", err);
+               return (-1);
+           }
+#endif
+       } else if (namadr_list_match(verp_clients, state->name, state->addr)
+                  && strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0
+                  && (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) {
+           if (arg[VERP_CMD_LEN] == 0) {
+               verp_delims = var_verp_delims;
+           } else {
+               verp_delims = arg + VERP_CMD_LEN + 1;
+               if (verp_delims_verify(verp_delims) != 0) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Error: %s needs two characters from %s",
+                                    VERP_CMD, var_verp_filter);
+                   return (-1);
+               }
+           }
+       } else {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "555 Unsupported option: %s", arg);
+           return (-1);
+       }
+    }
+    if (verp_delims && argv[2].strval[0] == 0) {
+       smtpd_chat_reply(state, "503 Error: %s requires non-null sender",
+                        VERP_CMD);
+       return (-1);
+    }
+    if (SMTPD_STAND_ALONE(state) == 0
+       && var_smtpd_delay_reject == 0
+       && (err = smtpd_check_mail(state, argv[2].strval)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       /* XXX Reset access map side effects. */
+       mail_reset(state);
+       return (-1);
+    }
+
+    /*
+     * Check the queue file space, if applicable.
+     */
+    if (!USE_SMTPD_PROXY(state)) {
+       if ((err = smtpd_check_size(state, state->msg_size)) != 0) {
+           smtpd_chat_reply(state, "%s", err);
+           return (-1);
+       }
+    }
+
+    /*
+     * No more early returns. The mail transaction is in progress.
+     */
+    state->time = time((time_t *) 0);
+    state->sender = mystrdup(argv[2].strval);
+    vstring_sprintf(state->instance, "%x.%lx.%x",
+                   var_pid, (unsigned long) state->time, state->seqno++);
+    if (verp_delims)
+       state->verp_delims = mystrdup(verp_delims);
+    if (USE_SMTPD_PROXY(state))
+       state->proxy_mail = mystrdup(STR(state->buffer));
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* mail_reset - reset MAIL command stuff */
+
+static void mail_reset(SMTPD_STATE *state)
+{
+    state->msg_size = 0;
+
+    /*
+     * Unceremoniously close the pipe to the cleanup service. The cleanup
+     * service will delete the queue file when it detects a premature
+     * end-of-file condition on input.
+     */
+    if (state->cleanup != 0) {
+       mail_stream_cleanup(state->dest);
+       state->dest = 0;
+       state->cleanup = 0;
+    }
+    state->err = 0;
+    if (state->queue_id != 0) {
+       myfree(state->queue_id);
+       state->queue_id = 0;
+    }
+    if (state->sender) {
+       myfree(state->sender);
+       state->sender = 0;
+    }
+    if (state->verp_delims) {
+       myfree(state->verp_delims);
+       state->verp_delims = 0;
+    }
+    if (state->proxy_mail) {
+       myfree(state->proxy_mail);
+       state->proxy_mail = 0;
+    }
+    if (state->saved_filter) {
+       myfree(state->saved_filter);
+       state->saved_filter = 0;
+    }
+    if (state->saved_redirect) {
+       myfree(state->saved_redirect);
+       state->saved_redirect = 0;
+    }
+    state->saved_flags = 0;
+#ifdef USE_SASL_AUTH
+    if (var_smtpd_sasl_enable)
+       smtpd_sasl_mail_reset(state);
+#endif
+    state->discard = 0;
+    VSTRING_RESET(state->instance);
+    VSTRING_TERMINATE(state->instance);
+
+    /*
+     * Try to be nice. Don't bother when we lost the connection. Don't bother
+     * waiting for a reply, it just increases latency.
+     */
+    if (state->proxy) {
+       (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT");
+       smtpd_proxy_close(state);
+    }
+    if (state->xforward.flags)
+       smtpd_xforward_reset(state);
+    if (state->prepend)
+       state->prepend = argv_free(state->prepend);
+}
+
+/* rcpt_cmd - process RCPT TO command */
+
+static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err;
+    int     narg;
+    char   *arg;
+
+    /*
+     * Sanity checks.
+     * 
+     * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
+     * command in which invalid character codes have been employed, and for
+     * which there are no other reasons for rejection, MUST reject that
+     * command with a 501 response. So much for the principle of "be liberal
+     * in what you accept, be strict in what you send".
+     */
+    if (!IN_MAIL_TRANSACTION(state)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "503 Error: need MAIL command");
+       return (-1);
+    }
+    if (argc < 3
+       || strcasecmp(argv[1].strval, "to:") != 0) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: RCPT TO: <address>");
+       return (-1);
+    }
+    if (argv[2].tokval == SMTPD_TOK_ERROR) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Bad recipient address syntax");
+       return (-1);
+    }
+    if ((err = extract_addr(state, argv + 2, REJECT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    for (narg = 3; narg < argc; narg++) {
+       arg = argv[narg].strval;
+       if (1) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "555 Unsupported option: %s", arg);
+           return (-1);
+       }
+    }
+    if (var_smtpd_rcpt_limit && state->rcpt_count >= var_smtpd_rcpt_limit) {
+       smtpd_chat_reply(state, "452 Error: too many recipients");
+       if (state->rcpt_overshoot++ < var_smtpd_rcpt_overlim)
+           return (0);
+       state->error_mask |= MAIL_ERROR_POLICY;
+       return (-1);
+    }
+    if (SMTPD_STAND_ALONE(state) == 0) {
+       if ((err = smtpd_check_rcpt(state, argv[2].strval)) != 0) {
+           smtpd_chat_reply(state, "%s", err);
+           return (-1);
+       }
+    }
+
+    /*
+     * Don't access the proxy, queue file, or queue file writer process until
+     * we have a valid recipient address.
+     */
+    if (state->proxy == 0 && state->cleanup == 0) {
+       if (state->proxy_mail) {
+           if (smtpd_proxy_open(state, var_smtpd_proxy_filt,
+                                var_smtpd_proxy_tmout, var_smtpd_proxy_ehlo,
+                                state->proxy_mail) != 0) {
+               smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+               return (-1);
+           }
+       } else {
+           mail_open_stream(state);
+       }
+
+       /*
+        * Log the queue ID with the message origin.
+        */
+#ifdef USE_SASL_AUTH
+       if (var_smtpd_sasl_enable)
+           smtpd_sasl_mail_log(state);
+       else
+#endif
+           msg_info("%s: client=%s", state->queue_id ?
+                    state->queue_id : "NOQUEUE", FORWARD_NAMADDR(state));
+    }
+
+    /*
+     * Proxy the recipient. OK, so we lied. If the real-time proxy rejects
+     * the recipient then we can have a proxy connection without having
+     * accepted a recipient.
+     */
+    if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK,
+                                       "%s", STR(state->buffer)) != 0) {
+       smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+       return (-1);
+    }
+
+    /*
+     * Store the recipient. Remember the first one.
+     * 
+     * Flush recipients to maintain a stiffer coupling with the next stage and
+     * to better utilize parallelism.
+     */
+    state->rcpt_count++;
+    if (state->recipient == 0)
+       state->recipient = mystrdup(argv[2].strval);
+    if (state->cleanup) {
+       rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval);
+       vstream_fflush(state->cleanup);
+    }
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* rcpt_reset - reset RCPT stuff */
+
+static void rcpt_reset(SMTPD_STATE *state)
+{
+    if (state->recipient) {
+       myfree(state->recipient);
+       state->recipient = 0;
+    }
+    state->rcpt_count = 0;
+    /* XXX Must flush the command history. */
+    state->rcpt_overshoot = 0;
+}
+
+/* data_cmd - process DATA command */
+
+static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
+{
+    char   *err;
+    char   *start;
+    int     len;
+    int     curr_rec_type;
+    int     prev_rec_type;
+    int     first = 1;
+    VSTRING *why = 0;
+    int     saved_err;
+    int     (*out_record) (VSTREAM *, int, const char *, int);
+    int     (*out_fprintf) (VSTREAM *, int, const char *,...);
+    VSTREAM *out_stream;
+    int     out_error;
+    char  **cpp;
+
+    /*
+     * Sanity checks. With ESMTP command pipelining the client can send DATA
+     * before all recipients are rejected, so don't report that as a protocol
+     * error.
+     */
+    if (state->rcpt_count == 0) {
+       if (!IN_MAIL_TRANSACTION(state)) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "503 Error: need RCPT command");
+       } else {
+           smtpd_chat_reply(state, "554 Error: no valid recipients");
+       }
+       return (-1);
+    }
+    if (argc != 1) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: DATA");
+       return (-1);
+    }
+    if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_data(state)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_MORE,
+                                       "%s", STR(state->buffer)) != 0) {
+       smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+       return (-1);
+    }
+
+    /*
+     * One level of indirection to choose between normal or proxied
+     * operation. We want to avoid massive code duplication within tons of
+     * if-else clauses.
+     */
+    if (state->proxy) {
+       out_stream = state->proxy;
+       out_record = smtpd_proxy_rec_put;
+       out_fprintf = smtpd_proxy_rec_fprintf;
+       out_error = CLEANUP_STAT_PROXY;
+    } else {
+       out_stream = state->cleanup;
+       out_record = rec_put;
+       out_fprintf = rec_fprintf;
+       out_error = CLEANUP_STAT_WRITE;
+    }
+
+    /*
+     * Flush out any access table actions that are delegated to the cleanup
+     * server, and that may trigger before we accept the first valid
+     * recipient.
+     * 
+     * Terminate the message envelope segment. Start the message content
+     * segment, and prepend our own Received: header. If there is only one
+     * recipient, list the recipient address.
+     */
+    if (state->cleanup) {
+       if (state->saved_filter)
+           rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", state->saved_filter);
+       if (state->saved_redirect)
+           rec_fprintf(state->cleanup, REC_TYPE_RDR, "%s", state->saved_redirect);
+       if (state->saved_flags)
+           rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags);
+       rec_fputs(state->cleanup, REC_TYPE_MESG, "");
+    }
+
+    /*
+     * PREPEND message headers.
+     */
+    if (state->prepend)
+       for (cpp = state->prepend->argv; *cpp; cpp++)
+           out_fprintf(out_stream, REC_TYPE_NORM, "%s", *cpp);
+
+    /*
+     * Suppress our own Received: header in the unlikely case that we are an
+     * intermediate proxy.
+     */
+    if (!state->proxy || state->xforward.flags == 0) {
+       out_fprintf(out_stream, REC_TYPE_NORM,
+                   "Received: from %s (%s [%s])",
+                   state->helo_name ? state->helo_name : state->name,
+                   state->name, state->addr);
+       if (state->rcpt_count == 1 && state->recipient) {
+           out_fprintf(out_stream, REC_TYPE_NORM,
+                       state->cleanup ? "\tby %s (%s) with %s id %s" :
+                       "\tby %s (%s) with %s",
+                       var_myhostname, var_mail_name,
+                       state->protocol, state->queue_id);
+           quote_822_local(state->buffer, state->recipient);
+           out_fprintf(out_stream, REC_TYPE_NORM,
+             "\tfor <%s>; %s", STR(state->buffer), mail_date(state->time));
+       } else {
+           out_fprintf(out_stream, REC_TYPE_NORM,
+                       state->cleanup ? "\tby %s (%s) with %s id %s;" :
+                       "\tby %s (%s) with %s;",
+                       var_myhostname, var_mail_name,
+                       state->protocol, state->queue_id);
+           out_fprintf(out_stream, REC_TYPE_NORM,
+                       "\t%s", mail_date(state->time));
+       }
+#ifdef RECEIVED_ENVELOPE_FROM
+       quote_822_local(state->buffer, state->sender);
+       out_fprintf(out_stream, REC_TYPE_NORM,
+                   "\t(envelope-from %s)", STR(state->buffer));
+#endif
+    }
+    smtpd_chat_reply(state, "354 End data with <CR><LF>.<CR><LF>");
+
+    /*
+     * Copy the message content. If the cleanup process has a problem, keep
+     * reading until the remote stops sending, then complain. Produce typed
+     * records from the SMTP stream so we can handle data that spans buffers.
+     * 
+     * XXX Force an empty record when the queue file content begins with
+     * whitespace, so that it won't be considered as being part of our own
+     * Received: header. What an ugly Kluge.
+     * 
+     * XXX Deal with UNIX-style From_ lines at the start of message content
+     * because sendmail permits it.
+     */
+    for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type) {
+       if (smtp_get(state->buffer, state->client, var_line_limit) == '\n')
+           curr_rec_type = REC_TYPE_NORM;
+       else
+           curr_rec_type = REC_TYPE_CONT;
+       start = vstring_str(state->buffer);
+       len = VSTRING_LEN(state->buffer);
+       if (first) {
+           if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
+               out_fprintf(out_stream, curr_rec_type,
+                           "X-Mailbox-Line: %s", start);
+               continue;
+           }
+           first = 0;
+           if (len > 0 && IS_SPACE_TAB(start[0]))
+               out_record(out_stream, REC_TYPE_NORM, "", 0);
+       }
+       if (prev_rec_type != REC_TYPE_CONT && *start == '.'
+           && (state->proxy == 0 ? (++start, --len) == 0 : len == 1))
+           break;
+       if (state->err == CLEANUP_STAT_OK
+           && out_record(out_stream, curr_rec_type, start, len) < 0)
+           state->err = out_error;
+    }
+
+    /*
+     * Send the end of DATA and finish the proxy connection. Set the
+     * CLEANUP_STAT_PROXY error flag in case of trouble.
+     * 
+     * XXX The low-level proxy output routines should set "state" error
+     * attributes. This requires making "state" a context attribute of the
+     * VSTREAM.
+     */
+    if (state->proxy) {
+       if (state->err == CLEANUP_STAT_OK) {
+           (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, ".");
+           if (state->err == CLEANUP_STAT_OK &&
+               *STR(state->proxy_buffer) != '2')
+               state->err = CLEANUP_STAT_CONT;
+       } else {
+           state->error_mask |= MAIL_ERROR_SOFTWARE;
+           state->err |= CLEANUP_STAT_PROXY;
+           vstring_sprintf(state->proxy_buffer,
+                           "451 Error: queue file write error");
+       }
+    }
+
+    /*
+     * Send the end-of-segment markers and finish the queue file record
+     * stream.
+     */
+    else {
+       if (state->err == CLEANUP_STAT_OK)
+           if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
+               || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
+               || vstream_fflush(state->cleanup))
+               state->err = CLEANUP_STAT_WRITE;
+       if (state->err == 0) {
+           why = vstring_alloc(10);
+           state->err = mail_stream_finish(state->dest, why);
+       } else
+           mail_stream_cleanup(state->dest);
+       state->dest = 0;
+       state->cleanup = 0;
+    }
+
+    /*
+     * Handle any errors. One message may suffer from multiple errors, so
+     * complain only about the most severe error. Forgive any previous client
+     * errors when a message was received successfully.
+     * 
+     * See also: qmqpd.c
+     */
+    if (state->err == CLEANUP_STAT_OK) {
+       state->error_count = 0;
+       state->error_mask = 0;
+       state->junk_cmds = 0;
+       if (state->queue_id)
+           smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id);
+       else
+           smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+    } else if ((state->err & CLEANUP_STAT_BAD) != 0) {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       smtpd_chat_reply(state, "451 Error: internal error %d", state->err);
+    } else if ((state->err & CLEANUP_STAT_SIZE) != 0) {
+       state->error_mask |= MAIL_ERROR_BOUNCE;
+       smtpd_chat_reply(state, "552 Error: message too large");
+    } else if ((state->err & CLEANUP_STAT_HOPS) != 0) {
+       state->error_mask |= MAIL_ERROR_BOUNCE;
+       smtpd_chat_reply(state, "554 Error: too many hops");
+    } else if ((state->err & CLEANUP_STAT_CONT) != 0) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       if (state->proxy_buffer)
+           smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+       else
+           smtpd_chat_reply(state, "550 Error: %s", LEN(why) ?
+                            STR(why) : "content rejected");
+    } else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
+       state->error_mask |= MAIL_ERROR_RESOURCE;
+       smtpd_chat_reply(state, "451 Error: queue file write error");
+    } else if ((state->err & CLEANUP_STAT_PROXY) != 0) {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+    } else {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       smtpd_chat_reply(state, "451 Error: internal error %d", state->err);
+    }
+
+    /*
+     * Disconnect after transmission must not be treated as "lost connection
+     * after DATA".
+     */
+    state->where = SMTPD_AFTER_DOT;
+
+    /*
+     * Cleanup. The client may send another MAIL command.
+     */
+    saved_err = state->err;
+    chat_reset(state, var_smtpd_hist_thrsh);
+    mail_reset(state);
+    rcpt_reset(state);
+    if (why)
+       vstring_free(why);
+    return (saved_err);
+}
+
+/* rset_cmd - process RSET */
+
+static int rset_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
+{
+
+    /*
+     * Sanity checks.
+     */
+    if (argc != 1) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: RSET");
+       return (-1);
+    }
+
+    /*
+     * Restore state to right after HELO/EHLO command.
+     */
+    chat_reset(state, var_smtpd_hist_thrsh);
+    mail_reset(state);
+    rcpt_reset(state);
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* noop_cmd - process NOOP */
+
+static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
+{
+
+    /*
+     * XXX 2821 incompatibility: Section 4.1.1.9 says that NOOP can have a
+     * parameter string which is to be ignored. NOOP instructions with
+     * parameters? Go figure.
+     * 
+     * RFC 2821 violates RFC 821, which says that NOOP takes no parameters.
+     */
+#ifdef RFC821_SYNTAX
+
+    /*
+     * Sanity checks.
+     */
+    if (argc != 1) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: NOOP");
+       return (-1);
+    }
+#endif
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* vrfy_cmd - process VRFY */
+
+static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err = 0;
+
+    /*
+     * The SMTP standard (RFC 821) disallows unquoted special characters in
+     * the VRFY argument. Common practice violates the standard, however.
+     * Postfix accomodates common practice where it violates the standard.
+     * 
+     * XXX Impedance mismatch! The SMTP command tokenizer preserves quoting,
+     * whereas the recipient restrictions checks expect unquoted (internal)
+     * address forms. Therefore we must parse out the address, or we must
+     * stop doing recipient restriction checks and lose the opportunity to
+     * say "user unknown" at the SMTP port.
+     * 
+     * XXX 2821 incompatibility and brain damage: Section 4.5.1 requires that
+     * VRFY is implemented. RFC 821 specifies that VRFY is optional. It gets
+     * even worse: section 3.5.3 says that a 502 (command recognized but not
+     * implemented) reply is not fully compliant.
+     * 
+     * Thus, an RFC 2821 compliant implementation cannot refuse to supply
+     * information in reply to VRFY queries. That is simply bogus. The only
+     * reply we could supply is a generic 252 reply. This causes spammers to
+     * add tons of bogus addresses to their mailing lists (spam harvesting by
+     * trying out large lists of potential recipient names with VRFY).
+     */
+#define SLOPPY 0
+
+    if (var_disable_vrfy_cmd) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       smtpd_chat_reply(state, "502 VRFY command is disabled");
+       return (-1);
+    }
+    if (argc < 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: VRFY address");
+       return (-1);
+    }
+    if (argc > 2)
+       collapse_args(argc - 1, argv + 1);
+    if ((err = extract_addr(state, argv + 1, REJECT_EMPTY_ADDR, SLOPPY)) != 0) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    if (SMTPD_STAND_ALONE(state) == 0
+       && (err = smtpd_check_rcpt(state, argv[1].strval)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+
+    /*
+     * XXX 2821 new feature: Section 3.5.1 requires that the VRFY response is
+     * either "full name <user@domain>" or "user@domain". Postfix replies
+     * with the address that was provided by the client, whether or not it is
+     * in fully qualified domain form or not.
+     * 
+     * Reply code 250 is reserved for the case where the address is verified;
+     * reply code 252 should be used when no definitive certainty exists.
+     */
+    smtpd_chat_reply(state, "252 %s", argv[1].strval);
+    return (0);
+}
+
+/* etrn_cmd - process ETRN command */
+
+static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    char   *err;
+
+    /*
+     * Sanity checks.
+     */
+    if (var_helo_required && state->helo_name == 0) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       smtpd_chat_reply(state, "503 Error: send HELO/EHLO first");
+       return (-1);
+    }
+    if (IN_MAIL_TRANSACTION(state)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "503 Error: MAIL transaction in progress");
+       return (-1);
+    }
+    if (argc != 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "500 Syntax: ETRN domain");
+       return (-1);
+    }
+    if (!ISALNUM(argv[1].strval[0]))
+       argv[1].strval++;
+    if (!valid_hostname(argv[1].strval, DONT_GRIPE)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Error: invalid parameter syntax");
+       return (-1);
+    }
+
+    /*
+     * XXX The implementation borrows heavily from the code that implements
+     * UCE restrictions. These typically return 450 or 550 when a request is
+     * rejected. RFC 1985 requires that 459 be sent when the server refuses
+     * to perform the request.
+     */
+    if (SMTPD_STAND_ALONE(state)) {
+       msg_warn("do not use ETRN in \"sendmail -bs\" mode");
+       smtpd_chat_reply(state, "458 Unable to queue messages");
+       return (-1);
+    }
+    if ((err = smtpd_check_etrn(state, argv[1].strval)) != 0) {
+       smtpd_chat_reply(state, "%s", err);
+       return (-1);
+    }
+    switch (flush_send(argv[1].strval)) {
+    case FLUSH_STAT_OK:
+       smtpd_chat_reply(state, "250 Queuing started");
+       return (0);
+    case FLUSH_STAT_DENY:
+       msg_warn("reject: ETRN %.100s... from %s",
+                argv[1].strval, state->namaddr);
+       smtpd_chat_reply(state, "459 <%s>: service unavailable",
+                        argv[1].strval);
+       return (-1);
+    case FLUSH_STAT_BAD:
+       msg_warn("bad ETRN %.100s... from %s", argv[1].strval, state->namaddr);
+       smtpd_chat_reply(state, "458 Unable to queue messages");
+       return (-1);
+    default:
+       msg_warn("unable to talk to fast flush service");
+       smtpd_chat_reply(state, "458 Unable to queue messages");
+       return (-1);
+    }
+}
+
+/* quit_cmd - process QUIT command */
+
+static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_argv)
+{
+
+    /*
+     * Don't bother checking the syntax.
+     */
+    smtpd_chat_reply(state, "221 Bye");
+
+    /*
+     * When the "." and quit replies are pipelined, make sure they are
+     * flushed now, to avoid repeated mail deliveries in case of a crash in
+     * the "clean up before disconnect" code.
+     */
+    vstream_fflush(state->client);
+    return (0);
+}
+
+/* xclient_cmd - override SMTP client attributes */
+
+static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    SMTPD_TOKEN *argp;
+    char   *attr_value;
+    char   *attr_name;
+    int     update_namaddr = 0;
+    int     peer_code;
+    static NAME_CODE peer_codes[] = {
+       XCLIENT_UNAVAILABLE, SMTPD_PEER_CODE_PERM,
+       XCLIENT_TEMPORARY, SMTPD_PEER_CODE_TEMP,
+       0, SMTPD_PEER_CODE_OK,
+    };
+    static NAME_CODE proto_names[] = {
+       MAIL_PROTO_SMTP, 1,
+       MAIL_PROTO_ESMTP, 2,
+       0, -1,
+    };
+
+    /*
+     * Sanity checks. The XCLIENT command does not override its own access
+     * control.
+     */
+    if (IN_MAIL_TRANSACTION(state)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "503 Error: MAIL transaction in progress");
+       return (-1);
+    }
+    if (argc < 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: %s attribute=value...",
+                        XCLIENT_CMD);
+       return (-1);
+    }
+    if (!xclient_allowed) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       smtpd_chat_reply(state, "554 Error: insufficient authorization");
+       return (-1);
+    }
+#define STREQ(x,y)     (strcasecmp((x), (y)) == 0)
+#define UPDATE_STR(s, v) do { \
+           if (s) myfree(s); \
+           s = (v) ? mystrdup(v) : 0; \
+       } while(0)
+#define NEUTER_CHARACTERS "<>()\\\";:@"
+
+    /*
+     * Iterate over all attribute=value elements.
+     */
+    for (argp = argv + 1; argp < argv + argc; argp++) {
+       attr_name = argp->strval;
+
+       /*
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
+        */
+       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 Error: attribute=value expected");
+           return (-1);
+       }
+       printable(attr_value, '?');
+
+       /*
+        * NAME=substitute SMTP client hostname. Also updates the client
+        * hostname lookup status code.
+        */
+       if (STREQ(attr_name, XCLIENT_NAME)) {
+           peer_code = name_code(peer_codes, NAME_CODE_FLAG_NONE, attr_value);
+           if (peer_code != SMTPD_PEER_CODE_OK) {
+               attr_value = CLIENT_NAME_UNKNOWN;
+           } else {
+               if (!valid_hostname(attr_value, DONT_GRIPE)
+                   || valid_hostaddr(attr_value, DONT_GRIPE)) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                    XCLIENT_NAME, attr_value);
+                   return (-1);
+               }
+           }
+           state->peer_code = peer_code;
+           UPDATE_STR(state->name, attr_value);
+           update_namaddr = 1;
+       }
+
+       /*
+        * ADDR=substitute SMTP client network address.
+        */
+       else if (STREQ(attr_name, XCLIENT_ADDR)) {
+           if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) {
+               attr_value = CLIENT_ADDR_UNKNOWN;
+           } else {
+               if (!valid_hostaddr(attr_value, DONT_GRIPE)) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                    XCLIENT_ADDR, attr_value);
+                   return (-1);
+               }
+           }
+           UPDATE_STR(state->addr, attr_value);
+           update_namaddr = 1;
+       }
+
+       /*
+        * HELO=substitute SMTP client HELO parameter. Censor special
+        * characters that could mess up message headers.
+        */
+       else if (STREQ(attr_name, XCLIENT_HELO)) {
+           if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) {
+               attr_value = CLIENT_HELO_UNKNOWN;
+           } else {
+               if (strlen(attr_value) > VALID_HOSTNAME_LEN) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                    XCLIENT_HELO, attr_value);
+                   return (-1);
+               }
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
+           }
+           UPDATE_STR(state->helo_name, attr_value);
+       }
+
+       /*
+        * PROTO=SMTP protocol name.
+        */
+       else if (STREQ(attr_name, XCLIENT_PROTO)) {
+           if (name_code(proto_names, NAME_CODE_FLAG_NONE, attr_value) < 0) {
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                XCLIENT_PROTO, attr_value);
+               return (-1);
+           }
+           UPDATE_STR(state->protocol, uppercase(attr_value));
+       }
+
+       /*
+        * Unknown attribute name. Complain.
+        */
+       else {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 Bad %s attribute name: %s",
+                            XCLIENT_CMD, attr_name);
+           return (-1);
+       }
+    }
+
+    /*
+     * Update the combined name and address when either has changed.
+     */
+    if (update_namaddr) {
+       if (state->namaddr)
+           myfree(state->namaddr);
+       state->namaddr =
+           concatenate(state->name, "[", state->addr, "]", (char *) 0);
+    }
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* xforward_cmd - forward logging attributes */
+
+static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
+{
+    SMTPD_TOKEN *argp;
+    char   *attr_value;
+    char   *attr_name;
+    int     updated = 0;
+    static NAME_CODE xforward_flags[] = {
+       XFORWARD_NAME, SMTPD_STATE_XFORWARD_NAME,
+       XFORWARD_ADDR, SMTPD_STATE_XFORWARD_ADDR,
+       XFORWARD_PROTO, SMTPD_STATE_XFORWARD_PROTO,
+       XFORWARD_HELO, SMTPD_STATE_XFORWARD_HELO,
+       0, 0,
+    };
+    int     flag;
+
+    /*
+     * Sanity checks.
+     */
+    if (IN_MAIL_TRANSACTION(state)) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "503 Error: MAIL transaction in progress");
+       return (-1);
+    }
+    if (argc < 2) {
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       smtpd_chat_reply(state, "501 Syntax: %s attribute=value...",
+                        XFORWARD_CMD);
+       return (-1);
+    }
+    if (!xforward_allowed) {
+       state->error_mask |= MAIL_ERROR_POLICY;
+       smtpd_chat_reply(state, "554 Error: insufficient authorization");
+       return (-1);
+    }
+
+    /*
+     * Initialize.
+     */
+    if (state->xforward.flags == 0)
+       smtpd_xforward_preset(state);
+
+    /*
+     * Iterate over all attribute=value elements.
+     */
+    for (argp = argv + 1; argp < argv + argc; argp++) {
+       attr_name = argp->strval;
+
+       /*
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
+        */
+       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 Error: attribute=value expected");
+           return (-1);
+       }
+       if (strlen(attr_value) > 255) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 Error: attribute value too long");
+           return (-1);
+       }
+       printable(attr_value, '?');
+
+       flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name);
+       switch (flag) {
+
+           /*
+            * NAME=up-stream host name, not necessarily in the DNS. Censor
+            * special characters that could mess up message headers.
+            */
+       case SMTPD_STATE_XFORWARD_NAME:
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
+               attr_value = CLIENT_NAME_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
+           }
+           UPDATE_STR(state->xforward.name, attr_value);
+           break;
+
+           /*
+            * ADDR=up-stream host network address, not necessarily on the
+            * Internet. Censor special characters that could mess up message
+            * headers.
+            */
+       case SMTPD_STATE_XFORWARD_ADDR:
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
+               attr_value = CLIENT_ADDR_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
+           }
+           UPDATE_STR(state->xforward.addr, attr_value);
+           break;
+
+           /*
+            * HELO=hostname that the up-stream MTA introduced itself with
+            * (not necessarily SMTP HELO). Censor special characters that
+            * could mess up message headers.
+            */
+       case SMTPD_STATE_XFORWARD_HELO:
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
+               attr_value = CLIENT_HELO_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
+           }
+           UPDATE_STR(state->xforward.helo_name, attr_value);
+           break;
+
+           /*
+            * PROTO=up-stream protocol, not necessarily SMTP or ESMTP.
+            * Censor special characters that could mess up message headers.
+            */
+       case SMTPD_STATE_XFORWARD_PROTO:
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
+               attr_value = CLIENT_PROTO_UNKNOWN;
+           } else {
+               if (strlen(attr_value) > 64) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                    XFORWARD_PROTO, attr_value);
+                   return (-1);
+               }
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
+           }
+           UPDATE_STR(state->xforward.protocol, attr_value);
+           break;
+
+           /*
+            * Unknown attribute name. Complain.
+            */
+       default:
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 Bad %s attribute name: %s",
+                            XFORWARD_CMD, attr_name);
+           return (-1);
+       }
+       updated |= flag;
+    }
+    state->xforward.flags |= updated;
+
+    /*
+     * Update the combined name and address when either has changed. Use only
+     * the name when no address is available.
+     */
+    if (updated & (SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR)) {
+       if (state->xforward.namaddr)
+           myfree(state->xforward.namaddr);
+       state->xforward.namaddr =
+           IS_AVAIL_CLIENT_ADDR(state->xforward.addr) ?
+           concatenate(state->xforward.name, "[",
+                       state->xforward.addr, "]",
+                       (char *) 0) : mystrdup(state->xforward.name);
+    }
+    smtpd_chat_reply(state, "250 Ok");
+    return (0);
+}
+
+/* chat_reset - notify postmaster and reset conversation log */
+
+static void chat_reset(SMTPD_STATE *state, int threshold)
+{
+
+    /*
+     * Notify the postmaster if there were errors. This usually indicates a
+     * client configuration problem, or that someone is trying nasty things.
+     * Either is significant enough to bother the postmaster. XXX Can't
+     * report problems when running in stand-alone mode: postmaster notices
+     * require availability of the cleanup service.
+     */
+    if (state->history != 0 && state->history->argc > threshold) {
+       if (SMTPD_STAND_ALONE(state) == 0
+           && (state->error_mask & state->notify_mask))
+           smtpd_chat_notify(state);
+       state->error_mask = 0;
+       smtpd_chat_reset(state);
+    }
+}
+
+ /*
+  * The table of all SMTP commands that we know. Set the junk limit flag on
+  * any command that can be repeated an arbitrary number of times without
+  * triggering a tarpit delay of some sort.
+  */
+typedef struct SMTPD_CMD {
+    char   *name;
+    int     (*action) (SMTPD_STATE *, int, SMTPD_TOKEN *);
+    int     flags;
+} SMTPD_CMD;
+
+#define SMTPD_CMD_FLAG_LIMIT    (1<<0) /* limit usage */
+#define SMTPD_CMD_FLAG_FORBID  (1<<1)  /* RFC 2822 mail header */
+
+static SMTPD_CMD smtpd_cmd_table[] = {
+    "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT,
+
+#ifdef USE_SASL_AUTH
+    "AUTH", smtpd_sasl_auth_cmd, 0,
+#endif
+
+    "MAIL", mail_cmd, 0,
+    "RCPT", rcpt_cmd, 0,
+    "DATA", data_cmd, 0,
+    "RSET", rset_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "NOOP", noop_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "QUIT", quit_cmd, 0,
+    "XCLIENT", xclient_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "XFORWARD", xforward_cmd, SMTPD_CMD_FLAG_LIMIT,
+    "Received:", 0, SMTPD_CMD_FLAG_FORBID,
+    "Reply-To:", 0, SMTPD_CMD_FLAG_FORBID,
+    "Message-ID:", 0, SMTPD_CMD_FLAG_FORBID,
+    "Subject:", 0, SMTPD_CMD_FLAG_FORBID,
+    "From:", 0, SMTPD_CMD_FLAG_FORBID,
+    "CONNECT", 0, SMTPD_CMD_FLAG_FORBID,
+    "User-Agent:", 0, SMTPD_CMD_FLAG_FORBID,
+    0,
+};
+
+static STRING_LIST *smtpd_noop_cmds;
+
+/* smtpd_proto - talk the SMTP protocol */
+
+static void smtpd_proto(SMTPD_STATE *state, const char *service)
+{
+    int     argc;
+    SMTPD_TOKEN *argv;
+    SMTPD_CMD *cmdp;
+    int     count;
+    int     crate;
+
+    /*
+     * Print a greeting banner and run the state machine. Read SMTP commands
+     * one line at a time. According to the standard, a sender or recipient
+     * address could contain an escaped newline. I think this is perverse,
+     * and anyone depending on this is really asking for trouble.
+     * 
+     * In case of mail protocol trouble, the program jumps back to this place,
+     * so that it can perform the necessary cleanup before talking to the
+     * next client. The setjmp/longjmp primitives are like a sharp tool: use
+     * with care. I would certainly recommend against the use of
+     * setjmp/longjmp in programs that change privilege levels.
+     * 
+     * In case of file system trouble the program terminates after logging the
+     * error and after informing the client. In all other cases (out of
+     * memory, panic) the error is logged, and the msg_cleanup() exit handler
+     * cleans up, but no attempt is made to inform the client of the nature
+     * of the problem.
+     */
+    smtp_timeout_setup(state->client, var_smtpd_tmout);
+
+    switch (vstream_setjmp(state->client)) {
+
+    default:
+       msg_panic("smtpd_proto: unknown error reading from %s[%s]",
+                 state->name, state->addr);
+       break;
+
+    case SMTP_ERR_TIME:
+       state->reason = "timeout";
+       smtpd_chat_reply(state, "421 %s Error: timeout exceeded",
+                        var_myhostname);
+       break;
+
+    case SMTP_ERR_EOF:
+       state->reason = "lost connection";
+       break;
+
+    case 0:
+
+       /*
+        * XXX The client connection count/rate control must be consistent in
+        * its use of client address information in connect and disconnect
+        * events. For now we exclude xclient authorized hosts from
+        * connection count/rate control.
+        */
+#ifdef SNAPSHOT
+       if (SMTPD_STAND_ALONE(state) == 0
+           && !xclient_allowed
+           && anvil_clnt
+           && !namadr_list_match(hogger_list, state->name, state->addr)
+           && anvil_clnt_connect(anvil_clnt, service, state->addr,
+                                 &count, &crate) == ANVIL_STAT_OK) {
+           if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) {
+               smtpd_chat_reply(state, "421 %s Error: too many connections from %s",
+                                var_myhostname, state->addr);
+               msg_warn("Too many connections: %d from %s for service %s",
+                        count, state->namaddr, service);
+               break;
+           }
+           if (var_smtpd_crate_limit > 0 && crate > var_smtpd_crate_limit) {
+               smtpd_chat_reply(state, "421 %s Error: too many connections from %s",
+                                var_myhostname, state->addr);
+               msg_warn("Too frequent connections: %d from %s for service %s",
+                        crate, state->namaddr, service);
+               break;
+           }
+       }
+#endif
+       /* XXX We use the real client for connect access control. */
+       if (SMTPD_STAND_ALONE(state) == 0
+           && var_smtpd_delay_reject == 0
+           && (state->access_denied = smtpd_check_client(state)) != 0) {
+           smtpd_chat_reply(state, "%s", state->access_denied);
+       } else {
+           smtpd_chat_reply(state, "220 %s", var_smtpd_banner);
+       }
+
+       for (;;) {
+           if (state->error_count >= var_smtpd_hard_erlim) {
+               state->reason = "too many errors";
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               smtpd_chat_reply(state, "421 %s Error: too many errors",
+                                var_myhostname);
+               break;
+           }
+           watchdog_pat();
+           smtpd_chat_query(state);
+           if ((argc = smtpd_token(vstring_str(state->buffer), &argv)) == 0) {
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               smtpd_chat_reply(state, "500 Error: bad syntax");
+               state->error_count++;
+               continue;
+           }
+           if (*var_smtpd_noop_cmds
+               && string_list_match(smtpd_noop_cmds, argv[0].strval)) {
+               smtpd_chat_reply(state, "250 Ok");
+               if (state->junk_cmds++ > var_smtpd_junk_cmd_limit)
+                   state->error_count++;
+               continue;
+           }
+           for (cmdp = smtpd_cmd_table; cmdp->name != 0; cmdp++)
+               if (strcasecmp(argv[0].strval, cmdp->name) == 0)
+                   break;
+           if (cmdp->name == 0) {
+               smtpd_chat_reply(state, "502 Error: command not implemented");
+               state->error_mask |= MAIL_ERROR_PROTOCOL;
+               state->error_count++;
+               continue;
+           }
+           if (cmdp->flags & SMTPD_CMD_FLAG_FORBID) {
+               msg_warn("%s sent non-SMTP command: %.100s",
+                        state->namaddr, vstring_str(state->buffer));
+               smtpd_chat_reply(state, "221 Error: I can break rules, too. Goodbye.");
+               break;
+           }
+           /* XXX We use the real client for connect access control. */
+           if (state->access_denied && cmdp->action != quit_cmd) {
+               smtpd_chat_reply(state, "503 Error: access denied for %s",
+                                state->namaddr);       /* RFC 2821 Sec 3.1 */
+               state->error_count++;
+               continue;
+           }
+           state->where = cmdp->name;
+           if (cmdp->action(state, argc, argv) != 0)
+               state->error_count++;
+           if ((cmdp->flags & SMTPD_CMD_FLAG_LIMIT)
+               && state->junk_cmds++ > var_smtpd_junk_cmd_limit)
+               state->error_count++;
+           if (cmdp->action == quit_cmd)
+               break;
+       }
+       break;
+    }
+
+    /*
+     * XXX The client connection count/rate control must be consistent in its
+     * use of client address information in connect and disconnect events.
+     * For now we exclude xclient authorized hosts from connection count/rate
+     * control.
+     */
+#ifdef SNAPSHOT
+    if (SMTPD_STAND_ALONE(state) == 0
+       && !xclient_allowed
+       && anvil_clnt
+       && !namadr_list_match(hogger_list, state->name, state->addr))
+       anvil_clnt_disconnect(anvil_clnt, service, state->addr);
+#endif
+
+    /*
+     * Log abnormal session termination, in case postmaster notification has
+     * been turned off. In the log, indicate the last recognized state before
+     * things went wrong. Don't complain about clients that go away without
+     * sending QUIT.
+     */
+    if (state->reason && state->where
+       && (strcmp(state->where, SMTPD_AFTER_DOT)
+           || strcmp(state->reason, "lost connection")))
+       msg_info("%s after %s from %s[%s]",
+                state->reason, state->where, state->name, state->addr);
+
+    /*
+     * Cleanup whatever information the client gave us during the SMTP
+     * dialog.
+     */
+    helo_reset(state);
+#ifdef USE_SASL_AUTH
+    if (var_smtpd_sasl_enable)
+       smtpd_sasl_auth_reset(state);
+#endif
+    chat_reset(state, 0);
+    mail_reset(state);
+    rcpt_reset(state);
+}
+
+/* smtpd_service - service one client */
+
+static void smtpd_service(VSTREAM *stream, char *service, char **argv)
+{
+    SMTPD_STATE state;
+
+    /*
+     * Sanity check. This service takes no command-line arguments.
+     */
+    if (argv[0])
+       msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+    /*
+     * This routine runs when a client has connected to our network port, or
+     * when the smtp server is run in stand-alone mode (input from pipe).
+     * 
+     * Look up and sanitize the peer name, then initialize some connection-
+     * specific state. When the name service is hosed, hostname lookup will
+     * take a while. This is why I always run a local name server on critical
+     * machines.
+     */
+    smtpd_state_init(&state, stream);
+    msg_info("connect from %s[%s]", state.name, state.addr);
+
+    /*
+     * XCLIENT must not override its own access control.
+     */
+    xclient_allowed =
+       namadr_list_match(xclient_hosts, state.name, state.addr);
+
+    /*
+     * Overriding XFORWARD access control makes no sense, either.
+     */
+    xforward_allowed =
+       namadr_list_match(xforward_hosts, state.name, state.addr);
+
+    /*
+     * See if we need to turn on verbose logging for this client.
+     */
+    debug_peer_check(state.name, state.addr);
+
+    /*
+     * Provide the SMTP service.
+     */
+    smtpd_proto(&state, service);
+
+    /*
+     * After the client has gone away, clean up whatever we have set up at
+     * connection time.
+     */
+    msg_info("disconnect from %s[%s]", state.name, state.addr);
+    smtpd_state_reset(&state);
+    debug_peer_restore();
+}
+
+/* pre_accept - see if tables have changed */
+
+static void pre_accept(char *unused_name, char **unused_argv)
+{
+    const char *table;
+
+    if ((table = dict_changed_name()) != 0) {
+       msg_info("table %s has changed -- restarting", table);
+       exit(0);
+    }
+}
+
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *unused_name, char **unused_argv)
+{
+
+    /*
+     * Initialize blacklist/etc. patterns before entering the chroot jail, in
+     * case they specify a filename pattern.
+     */
+    smtpd_noop_cmds = string_list_init(MATCH_FLAG_NONE, var_smtpd_noop_cmds);
+    verp_clients = namadr_list_init(MATCH_FLAG_NONE, var_verp_clients);
+    xclient_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xclient_hosts);
+    xforward_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xforward_hosts);
+#ifdef SNAPSHOT
+    hogger_list = namadr_list_init(MATCH_FLAG_NONE, var_smtpd_hoggers);
+#endif
+    if (getuid() == 0 || getuid() == var_owner_uid)
+       smtpd_check_init();
+    debug_peer_init();
+
+    if (var_smtpd_sasl_enable)
+#ifdef USE_SASL_AUTH
+       smtpd_sasl_initialize();
+
+    if (*var_smtpd_sasl_exceptions_networks)
+       sasl_exceptions_networks =
+           namadr_list_init(MATCH_FLAG_NONE,
+                            var_smtpd_sasl_exceptions_networks);
+#else
+       msg_warn("%s is true, but SASL support is not compiled in",
+                VAR_SMTPD_SASL_ENABLE);
+#endif
+
+    /*
+     * flush client.
+     */
+    flush_init();
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+
+    /*
+     * Initialize the receive transparency options: do we want unknown
+     * recipient checks, address mapping, header_body_checks?.
+     */
+    smtpd_input_transp_mask =
+    input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
+
+    /*
+     * Sanity checks. The queue_minfree value should be at least as large as
+     * (process_limit * message_size_limit) but that is unpractical, so we
+     * arbitrarily pick a number and require twice the message size limit.
+     */
+    if (var_queue_minfree > 0
+       && var_message_limit > 0
+       && var_queue_minfree / 1.5 < var_message_limit)
+       msg_warn("%s(%lu) should be at least 1.5*%s(%lu)",
+                VAR_QUEUE_MINFREE, (unsigned long) var_queue_minfree,
+                VAR_MESSAGE_LIMIT, (unsigned long) var_message_limit);
+
+    /*
+     * Connection rate management.
+     */
+#ifdef SNAPSHOT
+    if (var_smtpd_crate_limit || var_smtpd_cconn_limit)
+       anvil_clnt = anvil_clnt_create();
+#endif
+}
+
+/* main - the main program */
+
+int     main(int argc, char **argv)
+{
+    static CONFIG_INT_TABLE int_table[] = {
+       VAR_SMTPD_RCPT_LIMIT, DEF_SMTPD_RCPT_LIMIT, &var_smtpd_rcpt_limit, 1, 0,
+       VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0,
+       VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0,
+       VAR_QUEUE_MINFREE, DEF_QUEUE_MINFREE, &var_queue_minfree, 0, 0,
+       VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code, 0, 0,
+       VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code, 0, 0,
+       VAR_UNK_NAME_CODE, DEF_UNK_NAME_CODE, &var_unk_name_code, 0, 0,
+       VAR_UNK_ADDR_CODE, DEF_UNK_ADDR_CODE, &var_unk_addr_code, 0, 0,
+       VAR_RELAY_CODE, DEF_RELAY_CODE, &var_relay_code, 0, 0,
+       VAR_MAPS_RBL_CODE, DEF_MAPS_RBL_CODE, &var_maps_rbl_code, 0, 0,
+       VAR_ACCESS_MAP_CODE, DEF_ACCESS_MAP_CODE, &var_access_map_code, 0, 0,
+       VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0,
+       VAR_DEFER_CODE, DEF_DEFER_CODE, &var_defer_code, 0, 0,
+       VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
+       VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
+       VAR_SMTPD_RCPT_OVERLIM, DEF_SMTPD_RCPT_OVERLIM, &var_smtpd_rcpt_overlim, 1, 0,
+       VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0,
+       VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code, 0, 0,
+       VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code, 0, 0,
+       VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code, 0, 0,
+       VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code, 0, 0,
+       VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0,
+       VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
+       VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code, 0, 0,
+       VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0,
+#ifdef SNAPSHOT
+       VAR_SMTPD_CRATE_LIMIT, DEF_SMTPD_CRATE_LIMIT, &var_smtpd_crate_limit, 0, 0,
+       VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
+#endif
+       0,
+    };
+    static CONFIG_TIME_TABLE time_table[] = {
+       VAR_SMTPD_TMOUT, DEF_SMTPD_TMOUT, &var_smtpd_tmout, 1, 0,
+       VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
+       VAR_SMTPD_PROXY_TMOUT, DEF_SMTPD_PROXY_TMOUT, &var_smtpd_proxy_tmout, 1, 0,
+       VAR_VERIFY_POLL_DELAY, DEF_VERIFY_POLL_DELAY, &var_verify_poll_delay, 1, 0,
+       VAR_SMTPD_POLICY_TMOUT, DEF_SMTPD_POLICY_TMOUT, &var_smtpd_policy_tmout, 1, 0,
+       VAR_SMTPD_POLICY_IDLE, DEF_SMTPD_POLICY_IDLE, &var_smtpd_policy_idle, 1, 0,
+       VAR_SMTPD_POLICY_TTL, DEF_SMTPD_POLICY_TTL, &var_smtpd_policy_ttl, 1, 0,
+       0,
+    };
+    static CONFIG_BOOL_TABLE bool_table[] = {
+       VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required,
+       VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
+       VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env,
+       VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd,
+       VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
+       VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable,
+       VAR_BROKEN_AUTH_CLNTS, DEF_BROKEN_AUTH_CLNTS, &var_broken_auth_clients,
+       VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table,
+       VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from,
+       VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt,
+       0,
+    };
+    static CONFIG_STR_TABLE str_table[] = {
+       VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
+       VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+       VAR_CLIENT_CHECKS, DEF_CLIENT_CHECKS, &var_client_checks, 0, 0,
+       VAR_HELO_CHECKS, DEF_HELO_CHECKS, &var_helo_checks, 0, 0,
+       VAR_MAIL_CHECKS, DEF_MAIL_CHECKS, &var_mail_checks, 0, 0,
+       VAR_RCPT_CHECKS, DEF_RCPT_CHECKS, &var_rcpt_checks, 0, 0,
+       VAR_ETRN_CHECKS, DEF_ETRN_CHECKS, &var_etrn_checks, 0, 0,
+       VAR_DATA_CHECKS, DEF_DATA_CHECKS, &var_data_checks, 0, 0,
+       VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0,
+       VAR_RBL_REPLY_MAPS, DEF_RBL_REPLY_MAPS, &var_rbl_reply_maps, 0, 0,
+       VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
+       VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0,
+       VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
+       VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
+       VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
+       VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
+       VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
+       VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
+       VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0,
+       VAR_SMTPD_SASL_APPNAME, DEF_SMTPD_SASL_APPNAME, &var_smtpd_sasl_appname, 1, 0,
+       VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 0, 0,
+       VAR_SMTPD_SASL_EXCEPTIONS_NETWORKS, DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS, &var_smtpd_sasl_exceptions_networks, 0, 0,
+       VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
+       VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0,
+       VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0,
+       VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0,
+       VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0,
+       VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
+       VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
+       VAR_VERP_CLIENTS, DEF_VERP_CLIENTS, &var_verp_clients, 0, 0,
+       VAR_SMTPD_PROXY_FILT, DEF_SMTPD_PROXY_FILT, &var_smtpd_proxy_filt, 0, 0,
+       VAR_SMTPD_PROXY_EHLO, DEF_SMTPD_PROXY_EHLO, &var_smtpd_proxy_ehlo, 0, 0,
+       VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
+       VAR_XCLIENT_HOSTS, DEF_XCLIENT_HOSTS, &var_xclient_hosts, 0, 0,
+       VAR_XFORWARD_HOSTS, DEF_XFORWARD_HOSTS, &var_xforward_hosts, 0, 0,
+#ifdef SNAPSHOT
+       VAR_SMTPD_HOGGERS, DEF_SMTPD_HOGGERS, &var_smtpd_hoggers, 0, 0,
+#endif
+       0,
+    };
+    static CONFIG_RAW_TABLE raw_table[] = {
+       VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0,
+       VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply, 1, 0,
+       0,
+    };
+
+    /*
+     * Pass control to the single-threaded service skeleton.
+     */
+    single_server_main(argc, argv, smtpd_service,
+                      MAIL_SERVER_INT_TABLE, int_table,
+                      MAIL_SERVER_STR_TABLE, str_table,
+                      MAIL_SERVER_RAW_TABLE, raw_table,
+                      MAIL_SERVER_BOOL_TABLE, bool_table,
+                      MAIL_SERVER_TIME_TABLE, time_table,
+                      MAIL_SERVER_PRE_INIT, pre_jail_init,
+                      MAIL_SERVER_PRE_ACCEPT, pre_accept,
+                      MAIL_SERVER_POST_INIT, post_jail_init,
+                      0);
+}
index cefdb95040656c77975e160b2298013d42c5197d..b2a24623d7b0d7b2a7de84c44ddb206827329e58 100644 (file)
@@ -99,6 +99,10 @@ described in \fBregexp_table\fR(5).
 A table that always returns its name as lookup result. For example,
 \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
 result.
+.IP "\fBtcp\fR (read-only)"
+Perform lookups using a simple request-reply protocol that is
+described in tcp_table(5).
+This feature is not included with Postfix 2.1.
 .IP "\fBunix\fR (read-only)"
 A limited way to query the UNIX authentication database. The
 following tables are implemented:
index bf8c83a037e3c0094897b62e4ddb531c4b47f8cf..7379efd137907b546395f183558a1edeee19e665 100644 (file)
@@ -1116,8 +1116,8 @@ The location of Postfix HTML files that describe how to build,
 configure or operate a specific Postfix subsystem or feature.
 .SH ignore_mx_lookup_error (default: no)
 Ignore DNS MX lookups that produce no response.  By default,
-Postfix defers delivery and tries again after some delay.  This
-behavior is required by the SMTP standard.
+the Postfix SMTP client defers delivery and tries again after some
+delay.  This behavior is required by the SMTP standard.
 .PP
 Specify "\fBignore_mx_lookup_error = yes\fR" to force a DNS A record
 lookup instead. This violates the SMTP standard and can result in
@@ -2882,10 +2882,10 @@ Later Postfix versions always skip SMTP servers that greet with a
 Skip SMTP servers that greet with a 5XX status code (go away, do
 not try again later).
 .PP
-By default, Postfix moves on the next mail exchanger. Specify
-"smtp_skip_5xx_greeting = no" if Postfix should bounce the mail
-immediately. The default setting is incorrect, but it is what a
-lot of people expect to happen.
+By default, the Postfix SMTP client moves on the next mail
+exchanger. Specify "smtp_skip_5xx_greeting = no" if Postfix should
+bounce the mail immediately. The default setting is incorrect, but
+it is what a lot of people expect to happen.
 .SH smtp_skip_quit_response (default: yes)
 Do not wait for the response to the SMTP QUIT command.
 .SH smtp_xforward_timeout (default: 300s)
@@ -3501,7 +3501,8 @@ no sender-specified routing (user@elsewhere@domain).
 code for rejected requests (default: 554).
 .IP "\fBreject_unknown_recipient_domain\fR"
 Reject the request when the RCPT TO address has no DNS A or MX
-record.
+record and Postfix is not final destination for the recipient
+address.
 .br
 The unknown_address_reject_code parameter specifies
 the response code for rejected requests (default: 450).  The response
@@ -3793,12 +3794,13 @@ Enforces the reject_sender_login_mismatch restriction for
 unauthenticated clients only. This feature is available in
 Postfix version 2.1 and later.
 .IP "\fBreject_unknown_sender_domain\fR"
-Reject the request when the MAIL FROM address has no DNS A
-or MX record.
+Reject the request when the MAIL FROM address has no DNS A or
+MX record and Postfix is not final destination for the sender
+address.
 .br
-The unknown_address_reject_code parameter
-specifies the response code for rejected requests (default: 450).
-The response is always 450 in case of a temporary DNS error.
+The unknown_address_reject_code parameter specifies
+the response code for rejected requests (default: 450).  The response
+is always 450 in case of a temporary DNS error.
 .IP "\fBreject_unlisted_sender\fR"
 Reject the request when the MAIL FROM address is not listed in
 the list of valid recipients for its domain class. See the
index 6c5d8da0ab4c95504cbd5788529a25c00273bccc..094a75bed7960b409e463a7b29a46efdcf2714ef 100644 (file)
@@ -70,11 +70,9 @@ starts with whitespace continues a logical line.
 The \fIpattern\fR specifies an email address, a domain name, or
 a domain name hierarchy, as described in section "TABLE LOOKUP".
 
-The \fIresult\fR is of the form \fItransport\fB:\fInexthop\fR.
-The \fItransport\fR field specifies a mail delivery transport
-such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
-specifies where and how to deliver mail. More details are given
-in section "RESULT FORMAT".
+The \fIresult\fR is of the form \fItransport:nexthop\fR and
+specifies how or where to deliver mail. This is described in
+section "RESULT FORMAT".
 .SH "TABLE LOOKUP"
 .na
 .nf
@@ -111,14 +109,19 @@ mailer-daemon@hostname).
 .nf
 .ad
 .fi
+The lookup result is of the form \fItransport\fB:\fInexthop\fR.
+The \fItransport\fR field specifies a mail delivery transport
+such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
+specifies where and how to deliver mail.
+
 The transport field specifies the name of a mail delivery transport
 (the first name of a mail delivery service entry in the Postfix
 \fBmaster.cf\fR file).
 
 The interpretation of the nexthop field is transport
-dependent. In the case of SMTP, specify \fIhost\fR:\fIservice\fR for a
-non-default server port, and use [\fIhost\fR] or [\fIhost\fR]:\fIport\fR
-in order to disable MX (mail exchanger) DNS lookups. The [] form
+dependent. In the case of SMTP, specify a service on a non-default
+port as \fIhost\fR:\fIservice\fR, and disable MX (mail exchanger)
+DNS lookups with [\fIhost\fR] or [\fIhost\fR]:\fIport\fR. The [] form
 is required when you specify an IP address instead of a hostname.
 
 A null \fItransport\fR and null \fInexthop\fR result means "do
@@ -148,52 +151,53 @@ destinations.
 .ti +5
 \fB*         smtp:outbound-relay.my.domain\fR
 
-In order to send mail for \fBfoo.org\fR and its subdomains
-via the \fBuucp\fR transport to the UUCP host named \fBfoo\fR:
+In order to send mail for \fBexample.com\fR and its subdomains
+via the \fBuucp\fR transport to the UUCP host named \fBexample\fR:
 
 .ti +5
-\fBfoo.org      uucp:foo\fR
+\fBexample.com      uucp:example\fR
 .ti +5
-\fB\&.foo.org     uucp:foo\fR
+\fB\&.example.com     uucp:example\fR
 
 When no nexthop host name is specified, the destination domain
 name is used instead. For example, the following directs mail for
-\fIuser\fR@\fBfoo.org\fR via the \fBslow\fR transport to a mail
-exchanger for \fBfoo.org\fR.  The \fBslow\fR transport could be
-something that runs at most one delivery process at a time:
+\fIuser\fR@\fBexample.com\fR via the \fBslow\fR transport to a mail
+exchanger for \fBexample.com\fR.  The \fBslow\fR transport could be
+configured to run at most one delivery process at a time:
 
 .ti +5
-\fBfoo.org      slow:\fR
+\fBexample.com      slow:\fR
 
 When no transport is specified, Postfix uses the transport that
-matches the address domain class (see TRANSPORT FIELD discussion
-above).  The following sends all mail for \fBfoo.org\fR and its
-subdomains to host \fBgateway.foo.org\fR:
+matches the address domain class (see DESCRIPTION
+above).  The following sends all mail for \fBexample.com\fR and its
+subdomains to host \fBgateway.example.com\fR:
 
 .ti +5
-\fBfoo.org      :[gateway.foo.org]\fR
+\fBexample.com      :[gateway.example.com]\fR
 .ti +5
-\fB\&.foo.org     :[gateway.foo.org]\fR
+\fB\&.example.com     :[gateway.example.com]\fR
 
-In the above example, the [] are used to suppress MX lookups.
-The result would likely point to your local machine.
+In the above example, the [] suppress MX lookups.
+This prevents mail routing loops when your machine is primary MX
+host for \fBexample.com\fR.
 
 In the case of delivery via SMTP, one may specify
 \fIhostname\fR:\fIservice\fR instead of just a host:
 
 .ti +5
-\fBfoo.org      smtp:bar.org:2025\fR
+\fBexample.com      smtp:bar.example:2025\fR
 
-This directs mail for \fIuser\fR@\fBfoo.org\fR to host \fBbar.org\fR
+This directs mail for \fIuser\fR@\fBexample.com\fR to host \fBbar.example\fR
 port \fB2025\fR. Instead of a numerical port a symbolic name may be
-used. Specify [] around the hostname in order to disable MX lookups.
+used. Specify [] around the hostname if MX lookups must be disabled.
 
 The error mailer can be used to bounce mail:
 
 .ti +5
-\fB\&.foo.org      error:mail for *.foo.org is not deliverable\fR
+\fB\&.example.com     error:mail for *.example.com is not deliverable\fR
 
-This causes all mail for \fIuser\fR@\fIanything\fB.foo.org\fR
+This causes all mail for \fIuser\fR@\fIanything\fB.example.com\fR
 to be bounced.
 .SH "REGULAR EXPRESSION TABLES"
 .na
index ed340b3692ab0c956c4bab18d3cefeb83c88a0f9..15fe55913c0b52d14b8fa87522ef5c29d5798f73 100755 (executable)
@@ -450,6 +450,7 @@ exec sed '
        s/[<bB>]*smtp-[</bB>]*\n* *[<bB>]*sink[</bB>]*(1)/<a href="smtp-sink.1.html">&<\/a>/g
        s/[<bB>]*qmqp-[</bB>]*\n* *[<bB>]*source[</bB>]*(1)/<a href="qmqp-source.1.html">&<\/a>/g
        s/[<bB>]*qmqp-[</bB>]*\n* *[<bB>]*sink[</bB>]*(1)/<a href="qmqp-sink.1.html">&<\/a>/g
+       s/[<bB>]*qshape[</bB>]*(1)/<a href="qshape.1.html">&<\/a>/g
        s/[<bB>]*access[</bB>]*(5)/<a href="access.5.html">&<\/a>/g
        s/[<bB>]*aliases[</bB>]*(5)/<a href="aliases.5.html">&<\/a>/g
        s/[<bB>]*canonical[</bB>]*(5)/<a href="canonical.5.html">&<\/a>/g
@@ -594,6 +595,7 @@ exec sed '
 
        # Do nice links for smtp:host:port etc.
 
+       s/[[:<:]]\(error\):/<a href="error.8.html">\1<\/a>:/g
        s/[[:<:]]\(smtp\):/<a href="smtp.8.html">\1<\/a>:/g
        s/[[:<:]]\(lmtp\):/<a href="lmtp.8.html">\1<\/a>:/g
 
index ae84ba9da7dbc7d4c0774fefd6716bf2085dbcd8..ef14f64284d6f060890113d9df428b0a4863ba35 100644 (file)
@@ -118,17 +118,18 @@ on non-Postfix directories that need to be created in the process.
 <li> <p> Create the necessary mail_owner account and setgid_group
 group for exclusive use by Postfix. </p>
 
-<li> <p> Execute the post-install script in the Postfix configuration
-directory to set ownership and permission of Postfix files and
-directories. Specify any non-default settings for mail_owner or
-setgid_group on the post-install command line: </p>
+<li> <p> Execute the postfix command to set ownership and permission
+of Postfix files and directories, and to update Postfix configuration
+files. If necessary, specify any non-default settings for mail_owner
+or setgid_group on the postfix command line: </p>
 
 <pre>
-# sh post-install upgrade-package setgid_group=xxx mail_owner=yyy
+# postfix set-permissions upgrade-configuration \
+       setgid_group=xxx mail_owner=yyy
 </pre>
 
-<p> This will also update the main.cf and master.cf files if
-necessary. </p>
+<p> With Postfix versions before 2.1 you achieve the same result
+by invoking the post-install script directly. </p>
 
 </ul>
 
index 7cfd1e4331992a580f2a401f4e8d1abdc01b8e75..2418eba7bc96bef499f7e7acf5eadd8968693e41 100644 (file)
 
 <h2>Purpose of this document </h2>
 
-<p> This document describes the "qshape" program which helps the
+<p> This document describes the qshape(1) program which helps the
 administrator understand the Postfix queue message distribution
-sorted by time and by sender or recipient domain. qshape is bundled
-with the Postfix 2.1 source under the "auxiliary" directory. In
-order to understand the output of qshape, it useful to understand
-the various Postfix queues. To this end the role of each Postfix
-queue directory is described briefly in the "Background info:
-Postfix queue directories" section near the end of this document.
+sorted by time and by sender or recipient domain. qshape(1) is
+bundled with the Postfix 2.1 source under the "auxiliary" directory.
 </p>
 
+<p> In order to understand the output of qshape(1), it useful to
+understand the various Postfix queues. To this end the role of each
+Postfix queue directory is described briefly in the "Background
+info:  Postfix queue directories" section near the end of this
+document.  </p>
+
 <p> This document covers the following topics: </p>
 
 <ul>
@@ -71,8 +73,8 @@ queue</a></li>
 
 
 <p> When mail is draining slowly or the queue is unexpectedly large,
-run "qshape" as the super-user (root) to help zero in on the problem.
-The "qshape" program displays a tabular view of the Postfix queue
+run qshape(1) as the super-user (root) to help zero in on the problem.
+The qshape(1) program displays a tabular view of the Postfix queue
 contents.  </p>
 
 <ul>
@@ -217,7 +219,7 @@ $ egrep 'qmgr.*(panic|fatal|error|warning):' /var/log/maillog
 </blockquote>
 
 <p> When all else fails try the Postfix mailing list for help, but
-please don't forget to include the top 10 or 20 lines of "qshape"
+please don't forget to include the top 10 or 20 lines of qshape(1)
 output.  </p>
 
 <h2><a name="healthy">Example 1: Healthy queue</a></h2>
@@ -290,7 +292,7 @@ is the tail end of the time distribution, showing that short term
 arrival rates are moderate. Larger numbers and lower message ages
 are more indicative of current trouble. Old mail still going nowhere
 is largely harmless so long as the active and incoming queues are
-short. We can also see that the groups.msg.com undeliverables are
+short. We can also see that the groups.msn.com undeliverables are
 low rate steady stream rather than a concentrated dictionary attack
 that is now over. </p>
 
@@ -322,7 +324,7 @@ queues large and not shrinking despite very large delivery agent
 process limits.  The thread is archived at:
 http://groups.google.com/groups?th=636626c645f5bbde </p>
 
-<p> Using an older version of "qshape" it was quickly determined
+<p> Using an older version of qshape(1) it was quickly determined
 that all the messages were for just a few destinations: </p>
 
 <blockquote>
@@ -780,7 +782,7 @@ queue flushes.  </p>
 
 <h2><a name="credits">Credits</a></h2>
 
-<p> The "qshape" program was developed by Victor Duchovni of Morgan
+<p> The qshape(1) program was developed by Victor Duchovni of Morgan
 Stanley, who also wrote the initial version of this document.  </p>
 
 </body>
index bb3ed862b2454a7fcd8a4cf20516e84d6bfc3d4a..7d9ad751f8750519a57fa19987d4250711bfde1a 100644 (file)
@@ -105,7 +105,8 @@ to IP spoofing. </p>
         <i>...the usual stuff...</i>
 
 /etc/postfix/access:
-    all     permit_mynetworks,reject
+    all@my.domain   permit_mynetworks,reject
+    all@my.hostname permit_mynetworks,reject
 </pre>
 </blockquote>
 
index 6aeb575a57f93eb421fe87bb7ac4820239180a06..70dbcf8b200d50de141c008078dd5953a2cc2427 100644 (file)
@@ -122,13 +122,13 @@ the incoming queue.  </p>
 in the SMTPD_PROXY_README document.  This happens while Postfix
 receives mail, before it is stored in the incoming queue.  </p>
 
-<li> <p> Require that the client sends the HELO or EHLO command
+<li> <p> Requiring that the client sends the HELO or EHLO command
 before sending the MAIL FROM or ETRN command. This may cause problems
 with home-grown applications that send mail.  For this reason, the
 requirement is disabled by default ("smtpd_helo_required = no").
 </p>
 
-<li> <p> Disallow illegal syntax in MAIL FROM or RCPT TO commands.
+<li> <p> Disallowing illegal syntax in MAIL FROM or RCPT TO commands.
 This may cause problems with home-grown applications that send
 mail, and with ancient PC mail clients.  For this reason, the
 requirement is disabled by default ("strict_rfc821_envelopes =
@@ -136,21 +136,21 @@ no").  </p>
 
 <ul>
 
-<li> <p> Disallow RFC 822 address syntax (example: "MAIL FROM: the
+<li> <p> Disallowing RFC 822 address syntax (example: "MAIL FROM: the
 dude &lt;dude@example.com&gt;"). </p>
 
-<li> <p> Disallow addresses that are not enclosed with &lt;&gt;
+<li> <p> Disallowing addresses that are not enclosed with &lt;&gt;
 (example: "MAIL FROM: dude@example.com"). </p>
 
 </ul>
 
-<li> <p> Reject mail from a non-existent sender address.  This form
+<li> <p> Rejecting mail from a non-existent sender address.  This form
 of egress filtering helps to slow down worms and other malware, but
 may cause problems with home-grown software that sends out mail
 software with an unreplyable address. For this reason the requirement
 is disabled by default ("smtpd_reject_unlisted_sender = no").  </p>
 
-<li> <p> Reject mail for a non-existent recipient address.  This
+<li> <p> Rejecting mail for a non-existent recipient address.  This
 form of ingress filtering helps to keep the mail queue free of
 undeliverable MAILER-DAEMON messages. This requirement is enabled
 by default ("smtpd_reject_unlisted_recipient = yes"). </p>
index 8fe41b20e0ab571cb5bc92b86e27f3fe3da253c5..d07d2a83a02d7cfdd16faba29e987f642ef0381e 100644 (file)
@@ -1364,11 +1364,9 @@ is bounced, in order to stop a mailer loop.
 
 %PARAM ignore_mx_lookup_error no
 
-<p>
-Ignore DNS MX lookups that produce no response.  By default,
-Postfix defers delivery and tries again after some delay.  This
-behavior is required by the SMTP standard.
-</p>
+<p> Ignore DNS MX lookups that produce no response.  By default,
+the Postfix SMTP client defers delivery and tries again after some
+delay.  This behavior is required by the SMTP standard.  </p>
 
 <p>
 Specify "<b>ignore_mx_lookup_error = yes</b>" to force a DNS A record
@@ -3565,12 +3563,10 @@ Skip SMTP servers that greet with a 5XX status code (go away, do
 not try again later).
 </p>
 
-<p>
-By default, Postfix moves on the next mail exchanger. Specify
-"smtp_skip_5xx_greeting = no" if Postfix should bounce the mail
-immediately. The default setting is incorrect, but it is what a
-lot of people expect to happen.
-</p>
+<p> By default, the Postfix SMTP client moves on the next mail
+exchanger. Specify "smtp_skip_5xx_greeting = no" if Postfix should
+bounce the mail immediately. The default setting is incorrect, but
+it is what a lot of people expect to happen.  </p>
 
 %PARAM smtp_skip_quit_response yes
 
@@ -4443,7 +4439,8 @@ code for rejected requests (default: 554). </dd>
 <dt><b><a name="reject_unknown_recipient_domain">reject_unknown_recipient_domain</a></b></dt>
 
 <dd>Reject the request when the RCPT TO address has no DNS A or MX
-record. <br> The unknown_address_reject_code parameter specifies
+record and Postfix is not final destination for the recipient
+address. <br> The unknown_address_reject_code parameter specifies
 the response code for rejected requests (default: 450).  The response
 is always 450 in case of a temporary DNS error.</dd>
 
@@ -4767,10 +4764,11 @@ Postfix version 2.1 and later. </dd>
 
 <dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt>
 
-<dd>Reject the request when the MAIL FROM address has no DNS A
-or MX record. <br> The unknown_address_reject_code parameter
-specifies the response code for rejected requests (default: 450).
-The response is always 450 in case of a temporary DNS error. </dd>
+<dd>Reject the request when the MAIL FROM address has no DNS A or
+MX record and Postfix is not final destination for the sender
+address. <br> The unknown_address_reject_code parameter specifies
+the response code for rejected requests (default: 450).  The response
+is always 450 in case of a temporary DNS error. </dd>
 
 <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>
 
index b0ff1e520a643be8a83f46da1bb846af880bb3bb..23c95642162b104d72d5bee105d53b3a3d005e71 100644 (file)
 #      The \fIpattern\fR specifies an email address, a domain name, or
 #      a domain name hierarchy, as described in section "TABLE LOOKUP".
 #
-#      The \fIresult\fR is of the form \fItransport\fB:\fInexthop\fR.
-#      The \fItransport\fR field specifies a mail delivery transport
-#      such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
-#      specifies where and how to deliver mail. More details are given
-#      in section "RESULT FORMAT".
+#      The \fIresult\fR is of the form \fItransport:nexthop\fR and
+#      specifies how or where to deliver mail. This is described in
+#      section "RESULT FORMAT".
 # TABLE LOOKUP
 # .ad
 # .fi
 # RESULT FORMAT
 # .ad
 # .fi
+#      The lookup result is of the form \fItransport\fB:\fInexthop\fR.
+#      The \fItransport\fR field specifies a mail delivery transport
+#      such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
+#      specifies where and how to deliver mail.
+#
 #      The transport field specifies the name of a mail delivery transport
 #      (the first name of a mail delivery service entry in the Postfix
 #      \fBmaster.cf\fR file).
 #
 #      The interpretation of the nexthop field is transport
-#      dependent. In the case of SMTP, specify \fIhost\fR:\fIservice\fR for a
-#      non-default server port, and use [\fIhost\fR] or [\fIhost\fR]:\fIport\fR
-#      in order to disable MX (mail exchanger) DNS lookups. The [] form
+#      dependent. In the case of SMTP, specify a service on a non-default
+#      port as \fIhost\fR:\fIservice\fR, and disable MX (mail exchanger)
+#      DNS lookups with [\fIhost\fR] or [\fIhost\fR]:\fIport\fR. The [] form
 #      is required when you specify an IP address instead of a hostname.
 #
 #      A null \fItransport\fR and null \fInexthop\fR result means "do
 # .ti +5
 #      \fB*         smtp:outbound-relay.my.domain\fR
 #
-#      In order to send mail for \fBfoo.org\fR and its subdomains
-#      via the \fBuucp\fR transport to the UUCP host named \fBfoo\fR:
+#      In order to send mail for \fBexample.com\fR and its subdomains
+#      via the \fBuucp\fR transport to the UUCP host named \fBexample\fR:
 #
 # .ti +5
-#      \fBfoo.org      uucp:foo\fR
+#      \fBexample.com      uucp:example\fR
 # .ti +5
-#      \fB\&.foo.org     uucp:foo\fR
+#      \fB\&.example.com     uucp:example\fR
 #
 #      When no nexthop host name is specified, the destination domain
 #      name is used instead. For example, the following directs mail for
-#      \fIuser\fR@\fBfoo.org\fR via the \fBslow\fR transport to a mail
-#      exchanger for \fBfoo.org\fR.  The \fBslow\fR transport could be
-#      something that runs at most one delivery process at a time:
+#      \fIuser\fR@\fBexample.com\fR via the \fBslow\fR transport to a mail
+#      exchanger for \fBexample.com\fR.  The \fBslow\fR transport could be
+#      configured to run at most one delivery process at a time:
 #
 # .ti +5
-#      \fBfoo.org      slow:\fR
+#      \fBexample.com      slow:\fR
 #
 #      When no transport is specified, Postfix uses the transport that
-#      matches the address domain class (see TRANSPORT FIELD discussion
-#      above).  The following sends all mail for \fBfoo.org\fR and its
-#      subdomains to host \fBgateway.foo.org\fR:
+#      matches the address domain class (see DESCRIPTION
+#      above).  The following sends all mail for \fBexample.com\fR and its
+#      subdomains to host \fBgateway.example.com\fR:
 #
 # .ti +5
-#      \fBfoo.org      :[gateway.foo.org]\fR
+#      \fBexample.com      :[gateway.example.com]\fR
 # .ti +5
-#      \fB\&.foo.org     :[gateway.foo.org]\fR
+#      \fB\&.example.com     :[gateway.example.com]\fR
 #
-#      In the above example, the [] are used to suppress MX lookups.
-#      The result would likely point to your local machine.
+#      In the above example, the [] suppress MX lookups.
+#      This prevents mail routing loops when your machine is primary MX
+#      host for \fBexample.com\fR.
 #
 #      In the case of delivery via SMTP, one may specify
 #      \fIhostname\fR:\fIservice\fR instead of just a host:
 #
 # .ti +5
-#      \fBfoo.org      smtp:bar.org:2025\fR
+#      \fBexample.com      smtp:bar.example:2025\fR
 #
-#      This directs mail for \fIuser\fR@\fBfoo.org\fR to host \fBbar.org\fR
+#      This directs mail for \fIuser\fR@\fBexample.com\fR to host \fBbar.example\fR
 #      port \fB2025\fR. Instead of a numerical port a symbolic name may be
-#      used. Specify [] around the hostname in order to disable MX lookups.
+#      used. Specify [] around the hostname if MX lookups must be disabled.
 #
 #      The error mailer can be used to bounce mail:
 #
 # .ti +5
-#      \fB\&.foo.org      error:mail for *.foo.org is not deliverable\fR
+#      \fB\&.example.com     error:mail for *.example.com is not deliverable\fR
 #
-#      This causes all mail for \fIuser\fR@\fIanything\fB.foo.org\fR
+#      This causes all mail for \fIuser\fR@\fIanything\fB.example.com\fR
 #      to be bounced.
 # REGULAR EXPRESSION TABLES
 # .ad
 # CONFIGURATION PARAMETERS
 # .ad
 # .fi
-#       The following \fBmain.cf\fR parameters are especially relevant.  
+#       The following \fBmain.cf\fR parameters are especially relevant.
 #       The text below provides only a parameter summary. See
 #       postconf(5) for more details including examples.
 # .IP \fBempty_address_recipient\fR
index 184b07f7e3aaca925a2a656f7a641e439fa370c6..f1638b332aa34d72c54d092629f0b788249f606a 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only.
   */
-#define MAIL_RELEASE_DATE      "20040421"
+#define MAIL_RELEASE_DATE      "20040422"
 #define MAIL_VERSION_NUMBER    "2.2"
 
 #define VAR_MAIL_VERSION       "mail_version"
index d20bf0d8f5d3d990bcef7ddddd4d247ca45de750..07567361d769a075fcf309e3dd33ada32e111804 100644 (file)
 /*     A table that always returns its name as lookup result. For example,
 /*     \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
 /*     result.
+/* .IP "\fBtcp\fR (read-only)"
+/*     Perform lookups using a simple request-reply protocol that is
+/*     described in tcp_table(5).
+/*     This feature is not included with Postfix 2.1.
 /* .IP "\fBunix\fR (read-only)"
 /*     A limited way to query the UNIX authentication database. The
 /*     following tables are implemented:
index f3793e6201dd05f3cd5eab91212a8eb67f75dc00..292ac1fca4d8fe8ce98ff577705a28e0dd15d7d8 100644 (file)
@@ -149,6 +149,8 @@ smtpd.o: ../../include/quote_flags.h
 smtpd.o: ../../include/lex_822.h
 smtpd.o: ../../include/namadr_list.h
 smtpd.o: ../../include/input_transp.h
+smtpd.o: ../../include/anvil_clnt.h
+smtpd.o: ../../include/attr_clnt.h
 smtpd.o: ../../include/mail_server.h
 smtpd.o: smtpd_token.h
 smtpd.o: smtpd.h
@@ -230,6 +232,7 @@ smtpd_check.o: ../../include/verify_clnt.h
 smtpd_check.o: ../../include/deliver_request.h
 smtpd_check.o: ../../include/recipient_list.h
 smtpd_check.o: ../../include/input_transp.h
+smtpd_check.o: ../../include/is_header.h
 smtpd_check.o: smtpd.h
 smtpd_check.o: ../../include/mail_stream.h
 smtpd_check.o: smtpd_sasl_glue.h