]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20000821
authorWietse Venema <wietse@porcupine.org>
Mon, 21 Aug 2000 00:00:00 +0000 (00:00 +0000)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 23:12:18 +0000 (18:12 -0500)
32 files changed:
postfix/HISTORY
postfix/global/mail_version.h
postfix/global/opened.c
postfix/global/opened.h
postfix/html/Makefile.in
postfix/html/faq.html
postfix/html/nqmgr.8.html [new file with mode: 0644]
postfix/html/postalias.1.html
postfix/html/postmap.1.html
postfix/html/transport.5.html
postfix/man/Makefile.in
postfix/man/man1/postalias.1
postfix/man/man1/postmap.1
postfix/man/man5/transport.5
postfix/man/man8/nqmgr.8 [new file with mode: 0644]
postfix/nqmgr/qmgr.c
postfix/nqmgr/qmgr.h
postfix/nqmgr/qmgr_entry.c
postfix/nqmgr/qmgr_job.c
postfix/nqmgr/qmgr_message.c
postfix/nqmgr/qmgr_peer.c
postfix/nqmgr/qmgr_transport.c
postfix/postalias/postalias.c
postfix/postmap/postmap.c
postfix/proto/transport
postfix/qmgr/qmgr.c
postfix/qmgr/qmgr_message.c
postfix/smtp/smtp_connect.c
postfix/smtpd/smtpd.c
postfix/util/vstring.c
postfix/util/watchdog.c
postfix/util/watchdog.h

index c7e387e875bd2e2caee774294653c0dcd16a40b3..17b46c12801107c2bbe0cb094af059e8568d11c7 100644 (file)
@@ -4114,3 +4114,25 @@ Apologies for any names omitted.
 
        Robustness: make_dirs() now continues when a missing
        directory is created by another process.
+
+20000726
+
+       Robustness: added watchdog_pat() routine to keep the watchdog
+       quiet if a client stays connected for a lot of time. Files:
+       util/watchdog.[hc], smtpd/smtpd.c.
+
+20000729
+
+       Robustness: if relayhost is specified but the host does
+       not exist, defer mail instead of bouncing it (which would
+       lose the mail if the bounce would have to be delivered to
+       that same non-existent relayhost). Problem reported by
+       Chris Cooper @ maths.ox.ac.uk.
+
+20000821
+
+       Feature: added -r (replace) option to postalias and postmap.
+
+       Cleanup: smtpd now replies with 555 when the client sends
+       unrecognized RCPT TO parameters, as required by RFC 1869
+       (problem report by Robert Norris @ its.monash.edu.au).
index 67b1245e85178c1b9679eb57d721f6a453ef015e..9d6310f5bd13790a4444722d0b54491677494c56 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20000718"
+#define DEF_MAIL_VERSION       "Snapshot-20000821"
 extern char *var_mail_version;
 
 /* LICENSE
index a01399cc929091f149256308a3a800e4b8c598af..169af05cd07eb73cd5b6dd44594b4df03fa4a2fa 100644 (file)
@@ -6,10 +6,11 @@
 /* SYNOPSIS
 /*     #include <opened.h>
 /*
-/*     void    opened(queue_id, sender, size, format, ...)
+/*     void    opened(queue_id, sender, size, nrcpt, format, ...)
 /*     const char *queue_id;
 /*     const char *sender;
 /*     long    size;
+/*     int     nrcpt;
 /*     const char *format;
 /* DESCRIPTION
 /*     opened() logs that a message was successfully delivered.
@@ -23,6 +24,8 @@
 /*     Sender address.
 /* .IP size
 /*     Message content size.
+/* .IP nrcpt
+/*     Number of recipients.
 /* .IP format
 /*     Format of optional text.
 /* DIAGNOSTICS
 
 /* opened - log that a message was opened */
 
-void    opened(const char *queue_id, const char *sender, long size, const char *fmt,...)
+void    opened(const char *queue_id, const char *sender, long size, int nrcpt,
+                      const char *fmt,...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    vopened(queue_id, sender, size, fmt, ap);
+    vopened(queue_id, sender, size, nrcpt, fmt, ap);
     va_end(ap);
 }
 
-/* opened - log that a message was opened */
+/* vopened - log that a message was opened */
 
-void    vopened(const char *queue_id, const char *sender, long size, const char *fmt, va_list ap)
+void    vopened(const char *queue_id, const char *sender, long size, int nrcpt,
+                       const char *fmt, va_list ap)
 {
     VSTRING *text = vstring_alloc(100);
 
 #define TEXT (vstring_str(text))
 
     vstring_vsprintf(text, fmt, ap);
-    msg_info("%s: from=<%s>, size=%ld%s%s%s",
-        queue_id, sender, size, *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
+    msg_info("%s: from=<%s>, size=%ld, nrcpt=%d%s%s%s",
+            queue_id, sender, size, nrcpt,
+            *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
     vstring_free(text);
 }
index 618dd4221a1b6c9dd9a1704942af7d5872493311..3fc99598eaeef76f653600ca6ad2bce45a3d73b5 100644 (file)
  /*
   * External interface.
   */
-extern void PRINTFLIKE(4, 5) opened(const char *, const char *, long,
+extern void PRINTFLIKE(5, 6) opened(const char *, const char *, long, int,
                                            const char *,...);
-extern void vopened(const char *, const char *, long, const char *, va_list);
+extern void vopened(const char *, const char *, long, int,
+                           const char *, va_list);
 
 /* LICENSE
 /* .ad
index 63f98693aaf905a65c7a305eda40a615c5383eba..c701b0250ca4d198379dde3df0a37ca4a61d5592 100644 (file)
@@ -4,7 +4,8 @@ SHELL   = /bin/sh
 
 DAEMONS        =  bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
        lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
-       showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html
+       showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
+       nqmgr.8.html
 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 \
@@ -47,6 +48,10 @@ local.8.html: ../local/local.c
 master.8.html: ../master/master.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
+nqmgr.8.html: ../nqmgr/qmgr.c
+       srctoman $? | sed -e 's/qmgr[^_]/n&/' -e 's/QMGR[^_]/N&/' | \
+           nroff -man | man2html | postlink >$@
+
 pickup.8.html: ../pickup/pickup.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
index f53e7d25b9c97dfdc557a803cb1277e3d9cfdbfb..2d4d47e0aa1166b5c3f6e969a085fce9e361c382 100644 (file)
@@ -2080,7 +2080,7 @@ headers is sufficient to reliably implement a domain in a mailbox.
 
     /etc/postfix/virtual_regexp:
         /^virtual\.domain$/             whatever
-        /^(.*\)@virtual\.domain$/       joe+$1
+        /^(.*)@virtual\.domain$/        joe+$1
 </pre>
 
 <p>
diff --git a/postfix/html/nqmgr.8.html b/postfix/html/nqmgr.8.html
new file mode 100644 (file)
index 0000000..4a96531
--- /dev/null
@@ -0,0 +1,464 @@
+<html> <head> </head> <body> <pre>
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+<b>NAME</b>
+       qmgr - Postfix queue manager
+
+<b>SYNOPSIS</b>
+       <b>nqmgr</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+       The  <b>nqmgr</b>  daemon awaits the arrival of incoming mail and
+       arranges for its delivery via Postfix delivery  processes.
+       The actual mail routing strategy is delegated to the <a href="trivial-rewrite.8.html"><b>triv-</b>
+       <b>ial-rewrite</b>(8)</a> daemon.  This program  expects  to  be  run
+       from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
+
+       Mail  addressed  to  the  local  <b>double-bounce</b>  address is
+       silently discarded.  This stops potential loops caused  by
+       undeliverable bounce notifications.
+
+       Mail  addressed to a user listed in the optional <b>relocated</b>
+       database is bounced with a "user has  moved  to  <i>new_loca-</i>
+       <i>tion</i>" message. See <a href="relocated.5.html"><b>relocated</b>(5)</a> for a precise description.
+
+<b>MAIL</b> <b>QUEUES</b>
+       The <b>nqmgr</b> daemon maintains the following queues:
+
+       <b>incoming</b>
+              Inbound mail from the network, or mail picked up by
+              the local <b>pickup</b> agent from the <b>maildrop</b> directory.
+
+       <b>active</b> Messages that the  queue  manager  has  opened  for
+              delivery.  Only  a  limited  number  of messages is
+              allowed to enter the  <b>active</b>  queue  (leaky  bucket
+              strategy, for a fixed delivery rate).
+
+       <b>deferred</b>
+              Mail  that  could  not  be delivered upon the first
+              attempt. The queue manager  implements  exponential
+              backoff  by  doubling  the  time  between  delivery
+              attempts.
+
+       <b>corrupt</b>
+              Unreadable or damaged queue files  are  moved  here
+              for inspection.
+
+<b>DELIVERY</b> <b>STATUS</b> <b>REPORTS</b>
+       The <b>nqmgr</b> daemon keeps an eye on per-message delivery sta-
+       tus reports in  the  following  directories.  Each  status
+       report file has the same name as the corresponding message
+       file:
+
+       <b>bounce</b> Per-recipient status information about why mail  is
+              bounced.    These   files  are  maintained  by  the
+              <a href="bounce.8.html"><b>bounce</b>(8)</a> daemon.
+
+       <b>defer</b>  Per-recipient status information about why mail  is
+
+
+
+                                                                1
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+              delayed.    These   files  are  maintained  by  the
+              <a href="defer.8.html"><b>defer</b>(8)</a> daemon.
+
+       The <b>nqmgr</b> daemon is responsible for asking  the  <a href="bounce.8.html"><b>bounce</b>(8)</a>
+       or <a href="defer.8.html"><b>defer</b>(8)</a> daemons to send non-delivery reports.
+
+<b>STRATEGIES</b>
+       The  queue  manager implements a variety of strategies for
+       either opening queue files (input) or for message delivery
+       (output).
+
+       <b>leaky</b> <b>bucket</b>
+              This  strategy limits the number of messages in the
+              <b>active</b> queue and prevents the  queue  manager  from
+              running out of memory under heavy load.
+
+       <b>fairness</b>
+              When  the  <b>active</b> queue has room, the queue manager
+              takes one message from the <b>incoming</b> queue  and  one
+              from the <b>deferred</b> queue. This prevents a large mail
+              backlog from blocking the delivery of new mail.
+
+       <b>slow</b> <b>start</b>
+              This strategy eliminates "thundering herd" problems
+              by slowly adjusting the number of parallel deliver-
+              ies to the same destination.
+
+       <b>round</b> <b>robin</b>
+              The queue manager sorts delivery requests by desti-
+              nation.   Round-robin selection prevents one desti-
+              nation from dominating deliveries to other destina-
+              tions.
+
+       <b>exponential</b> <b>backoff</b>
+              Mail  that  cannot  be  delivered  upon  the  first
+              attempt is deferred.   The  time  interval  between
+              delivery attempts is doubled after each attempt.
+
+       <b>destination</b> <b>status</b> <b>cache</b>
+              The   queue  manager  avoids  unnecessary  delivery
+              attempts by  maintaining  a  short-term,  in-memory
+              list of unreachable destinations.
+
+       <b>preemptive</b> <b>message</b> <b>scheduling</b>
+              The  queue manager attempts to minimize the average
+              per-recipient delay while still preserving the cor-
+              rect per-message delays, using a sophisticated pre-
+              emptive message scheduling.
+
+<b>TRIGGERS</b>
+       On an idle system, the queue manager waits for the arrival
+       of  trigger  events,  or it waits for a timer to go off. A
+       trigger is a one-byte message.  Depending on  the  message
+       received,  the queue manager performs one of the following
+
+
+
+                                                                2
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+       actions (the message is followed by the symbolic  constant
+       used internally by the software):
+
+       <b>D</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>DEFERRED)</b>
+              Start  a  deferred queue scan.  If a deferred queue
+              scan is already in  progress,  that  scan  will  be
+              restarted as soon as it finishes.
+
+       <b>I</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>INCOMING)</b>
+              Start  an incoming queue scan. If an incoming queue
+              scan is already in  progress,  that  scan  will  be
+              restarted as soon as it finishes.
+
+       <b>A</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>ALL)</b>
+              Ignore deferred queue file time stamps. The request
+              affects the next deferred queue scan.
+
+       <b>F</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>FLUSH</b><i>_</i><b>DEAD)</b>
+              Purge all information  about  dead  transports  and
+              destinations.
+
+       <b>W</b> <b>(TRIGGER</b><i>_</i><b>REQ</b><i>_</i><b>WAKEUP)</b>
+              Wakeup  call,  This is used by the master server to
+              instantiate servers that should not  go  away  for-
+              ever.  The  action  is  to  start an incoming queue
+              scan.
+
+       The <b>nqmgr</b> daemon reads an entire buffer worth of triggers.
+       Multiple  identical  trigger  requests  are collapsed into
+       one, and trigger requests are sorted so that <b>A</b> and <b>F</b>  pre-
+       cede  <b>D</b>  and  <b>I</b>.  Thus, in order to force a deferred queue
+       run, one would request <b>A</b> <b>F</b> <b>D</b>; in order to notify the queue
+       manager of the arrival of new mail one would request <b>I</b>.
+
+<b>STANDARDS</b>
+       None.  The <b>nqmgr</b> daemon does not interact with the outside
+       world.
+
+<b>SECURITY</b>
+       The <b>nqmgr</b> daemon is not security sensitive. It reads  sin-
+       gle-character  messages  from  untrusted  local users, and
+       thus may be susceptible to denial of service attacks.  The
+       <b>nqmgr</b>  daemon  does  not talk to the outside world, and it
+       can be run at fixed low privilege in a  chrooted  environ-
+       ment.
+
+<b>DIAGNOSTICS</b>
+       Problems and transactions are logged to the syslog daemon.
+       Corrupted message files are saved to the <b>corrupt</b> queue for
+       further inspection.
+
+       Depending  on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+       the postmaster is notified of bounces and of  other  trou-
+       ble.
+
+
+
+                                                                3
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+<b>BUGS</b>
+       A  single  queue  manager  process has to compete for disk
+       access with multiple front-end processes such as <b>smtpd</b>.  A
+       sudden  burst  of  inbound mail can negatively impact out-
+       bound delivery rates.
+
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+       The following <b>main.cf</b> parameters are  especially  relevant
+       to  this  program. See the Postfix <b>main.cf</b> file for syntax
+       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
+       command after a configuration change.
+
+<b>Miscellaneous</b>
+       <b>allow</b><i>_</i><b>min</b><i>_</i><b>user</b>
+              Do  not  bounce recipient addresses that begin with
+              '-'.
+
+       <b>relocated</b><i>_</i><b>maps</b>
+              Tables with contact information for users, hosts or
+              domains that no longer exist. See <a href="relocated.5.html"><b>relocated</b>(5)</a>.
+
+       <b>queue</b><i>_</i><b>directory</b>
+              Top-level directory of the Postfix queue.
+
+<b>Active</b> <b>queue</b> <b>controls</b>
+       In  the text below, <i>transport</i> is the first field in a <b>mas-</b>
+       <b>ter.cf</b> entry.
+
+       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>active</b><i>_</i><b>limit</b>
+              Limit the number of messages in the active queue.
+
+       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Limit the number of in-memory recipients.
+
+              This parameter also limits the size of  the  short-
+              term, in-memory destination cache.
+
+       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>minimum</b>
+              Per message minimum of in-memory recipients.
+
+       <b>default</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Default limit on the number of in-memory recipients
+              per transport.
+
+       <i>transport_</i><b>recipient</b><i>_</i><b>limit</b>
+              Limit on the number of  in-memory  recipients,  for
+              the named message <i>transport</i>.
+
+       <b>default</b><i>_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Default  limit on the total number of per transport
+              in-memory recipients that the  preempting  messages
+              can have.
+
+
+
+
+
+                                                                4
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+       <i>transport_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Limit  on  the number of in-memory recipients which
+              all preempting messages delivered by the  transport
+              <i>transport</i> can have.
+
+<b>Timing</b> <b>controls</b>
+       <b>min</b><i>_</i><b>backoff</b>
+              Minimal  time  in seconds between delivery attempts
+              of a deferred message.
+
+              This parameter also limits the time an  unreachable
+              destination  is  kept  in the short-term, in-memory
+              destination status cache.
+
+       <b>max</b><i>_</i><b>backoff</b>
+              Maximal time in seconds between  delivery  attempts
+              of a deferred message.
+
+       <b>maximal</b><i>_</i><b>queue</b><i>_</i><b>lifetime</b>
+              Maximal  time in days a message is queued before it
+              is sent back as undeliverable.
+
+       <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
+              Time in seconds between deferred queue scans. Queue
+              scans do not overlap.
+
+       <b>transport</b><i>_</i><b>retry</b><i>_</i><b>time</b>
+              Time  in seconds between attempts to contact a bro-
+              ken delivery transport.
+
+<b>Concurrency</b> <b>controls</b>
+       <b>initial</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b>
+              Initial per-destination concurrency level for  par-
+              allel delivery to the same destination.
+
+       <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
+              Default  limit on the number of parallel deliveries
+              to the same destination.
+
+       <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
+              Limit on the number of parallel deliveries  to  the
+              same  destination,  for delivery via the named mes-
+              sage <i>transport</i>.
+
+<b>Recipient</b> <b>controls</b>
+       <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Default limit on the number of recipients per  mes-
+              sage transfer.
+
+       <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+              Limit  on  the  number  of  recipients  per message
+              transfer, for the named message <i>transport</i>.
+
+
+
+
+
+                                                                5
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+<b>Message</b> <b>scheduling</b>
+       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b> (valid range: 0,2,3...)
+              This parameter basically controls how often a  mes-
+              sage  delivered  by  <i>transport</i>  <b>can</b> <b>be</b> <b>preempted</b> <b>by</b>
+              <b>another</b> <b>message.</b>  <b>An</b> <b>internal</b> <b>per-message/transport</b>
+              <b>counter</b>  <b>is</b>  <b>incremented</b>  <b>by</b>  <b>one</b>  <b>for</b>  <b>each</b> <i>trans-</i>
+              <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b>   deliveries   handled   by
+              <i>transport</i>.  This  counter  represents the number of
+              "available delivery slots" for use  by  other  mes-
+              sages.  Current message can be preempted by another
+              message when that other message  can  be  delivered
+              using  less  <i>tranpsort</i> agents than the value of the
+              "available delivery slots" counter.
+
+              Value equal to 0 disables  the  message  preemption
+              for <i>transport</i>.
+
+       <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b>
+              Message preemption is not attempted at all whenever
+              a message  that  can't  ever  accumulate  at  least
+              <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b> available delivery
+              slots is being delivered by <i>transport</i>.
+
+       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> (valid range: 0..100)
+
+       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>
+              These parameters speed up the moment when a message
+              preemption  can  happen.   Instead of waiting until
+              the full  amount  of  delivery  slots  required  is
+              available,  the  preemption  can happen when <i>trans-</i>
+              <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> percent of the required
+              amount   plus   <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>  still
+              remains to  be  accumulated.  Note  that  the  full
+              amount  will  still  have  to be accumulated before
+              another preemption can take place later.
+
+       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b>
+
+       <b>default</b><i>_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b>
+
+       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b>
+
+       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>
+              Default values for the transport  specific  parame-
+              ters described above.
+
+<b>SEE</b> <b>ALSO</b>
+       <a href="master.8.html">master(8)</a>, process manager
+       <a href="relocated.5.html">relocated(5)</a>, format of the "user has moved" table
+       syslogd(8) system logging
+       <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, address routing
+
+<b>LICENSE</b>
+       The  Secure  Mailer  license must be distributed with this
+
+
+
+                                                                6
+
+
+
+
+
+NQMGR(8)                                                 NQMGR(8)
+
+
+       software.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                7
+
+
+</pre> </body> </html>
index c66bc04ae28f6e002c9165bd5657f5b8de7ff682..e8540371fc65cf2148466703c5b3525c8624e67d 100644 (file)
@@ -9,7 +9,7 @@ POSTALIAS(1)                                         POSTALIAS(1)
        postalias - Postfix alias database maintenance
 
 <b>SYNOPSIS</b>
-       <b>postalias</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
+       <b>postalias</b> [<b>-Ninrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
        [<i>file_type</i>:]<i>file_name</i> ...
 
 <b>DESCRIPTION</b>
@@ -55,10 +55,10 @@ POSTALIAS(1)                                         POSTALIAS(1)
               The exit status is non-zero if the requested infor-
               mation was not found.
 
-       <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
-              tiple <b>-v</b> options  make  the  software  increasingly
-              verbose.
+       <b>-r</b>     When  updating a table, do not warn about duplicate
+              entries; silently replace them.
 
+       <b>-v</b>     Enable  verbose  logging  for  debugging  purposes.
 
 
 
@@ -71,7 +71,10 @@ POSTALIAS(1)                                         POSTALIAS(1)
 POSTALIAS(1)                                         POSTALIAS(1)
 
 
-       <b>-w</b>     When  updating a table, do not warn about duplicate
+              Multiple  <b>-v</b> options make the software increasingly
+              verbose.
+
+       <b>-w</b>     When updating a table, do not warn about  duplicate
               entries; silently ignore them.
 
        Arguments:
@@ -79,35 +82,35 @@ POSTALIAS(1)                                         POSTALIAS(1)
        <i>file_type</i>
               The type of database to be produced.
 
-              <b>btree</b>  The  output   is   a   btree   file,   named
-                     <i>file_name</i><b>.db</b>.   This  is  available  only on
+              <b>btree</b>  The   output   is   a   btree   file,  named
+                     <i>file_name</i><b>.db</b>.  This  is  available  only  on
                      systems with support for <b>db</b> databases.
 
-              <b>dbm</b>    The output  consists  of  two  files,  named
-                     <i>file_name</i><b>.pag</b>  and  <i>file_name</i><b>.dir</b>.   This is
-                     available only on systems with  support  for
+              <b>dbm</b>    The  output  consists  of  two  files, named
+                     <i>file_name</i><b>.pag</b> and  <i>file_name</i><b>.dir</b>.   This  is
+                     available  only  on systems with support for
                      <b>dbm</b> databases.
 
-              <b>hash</b>   The   output   is   a   hashed  file,  named
-                     <i>file_name</i><b>.db</b>.  This  is  available  only  on
+              <b>hash</b>   The  output  is   a   hashed   file,   named
+                     <i>file_name</i><b>.db</b>.   This  is  available  only on
                      systems with support for <b>db</b> databases.
 
-              When  no  <i>file_type</i> is specified, the software uses
-              the database type specified via  the  <b>database</b><i>_</i><b>type</b>
-              configuration  parameter.   The  default  value for
+              When no <i>file_type</i> is specified, the  software  uses
+              the  database  type specified via the <b>database</b><i>_</i><b>type</b>
+              configuration parameter.   The  default  value  for
               this parameter depends on the host environment.
 
        <i>file_name</i>
-              The name of the alias  database  source  file  when
+              The  name  of  the  alias database source file when
               rebuilding a database.
 
 <b>DIAGNOSTICS</b>
-       Problems  are logged to the standard error stream. No out-
+       Problems are logged to the standard error stream. No  out-
        put means no problems were detected. Duplicate entries are
        skipped and are flagged with a warning.
 
 <b>BUGS</b>
-       The  "delete  key" support is limited to one delete opera-
+       The "delete key" support is limited to one  delete  opera-
        tion per command invocation.
 
 <b>ENVIRONMENT</b>
@@ -118,13 +121,10 @@ POSTALIAS(1)                                         POSTALIAS(1)
               Enable verbose logging for debugging purposes.
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The following <b>main.cf</b> parameters are  especially  relevant
-       to  this  program. See the Postfix <b>main.cf</b> file for syntax
+       The  following  <b>main.cf</b> parameters are especially relevant
+       to this program. See the Postfix <b>main.cf</b> file  for  syntax
        details and for default values.
 
-       <b>database</b><i>_</i><b>type</b>
-              Default alias database type. On many UNIX  systems,
-              the default type is either <b>dbm</b> or <b>hash</b>.
 
 
 
@@ -137,15 +137,19 @@ POSTALIAS(1)                                         POSTALIAS(1)
 POSTALIAS(1)                                         POSTALIAS(1)
 
 
+       <b>database</b><i>_</i><b>type</b>
+              Default  alias database type. On many UNIX systems,
+              the default type is either <b>dbm</b> or <b>hash</b>.
+
 <b>STANDARDS</b>
-       RFC 822 (ARPA Internet Text Messages)
+       <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
 
 <b>SEE</b> <b>ALSO</b>
        <a href="aliases.5.html">aliases(5)</a> format of alias database input file.
        <a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
 
 <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>
@@ -185,10 +189,6 @@ POSTALIAS(1)                                         POSTALIAS(1)
 
 
 
-
-
-
-
 
 
 
index 9dee8109d266b4c3f4c5d7ef08e3bdecf6c8f7a3..b81278cbc96e9d090b8b65702bd3b3d06a0f93a5 100644 (file)
@@ -9,7 +9,7 @@ POSTMAP(1)                                             POSTMAP(1)
        postmap - Postfix lookup table management
 
 <b>SYNOPSIS</b>
-       <b>postmap</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
+       <b>postmap</b> [<b>-Ninrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
        [<i>file_type</i>:]<i>file_name</i> ...
 
 <b>DESCRIPTION</b>
@@ -86,11 +86,14 @@ POSTMAP(1)                                             POSTMAP(1)
               The exit status is non-zero if the requested infor-
               mation was not found.
 
+       <b>-r</b>     When updating a table, do not warn about  duplicate
+              entries; silently replace them.
+
        <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>-w</b>     When updating a table, do not warn about  duplicate
+       <b>-w</b>     When  updating a table, do not warn about duplicate
               entries; silently ignore them.
 
        Arguments:
@@ -98,33 +101,30 @@ POSTMAP(1)                                             POSTMAP(1)
        <i>file_type</i>
               The type of database to be produced.
 
-              <b>btree</b>  The  output  file  is  a  btree  file, named
-                     <i>file_name</i><b>.db</b>.  This  is  available  only  on
+              <b>btree</b>  The output  file  is  a  btree  file,  named
+                     <i>file_name</i><b>.db</b>.   This  is  available  only on
                      systems with support for <b>db</b> databases.
 
-              <b>dbm</b>    The  output  consists  of  two  files, named
-                     <i>file_name</i><b>.pag</b> and  <i>file_name</i><b>.dir</b>.   This  is
-                     available  only  on systems with support for
+              <b>dbm</b>    The output  consists  of  two  files,  named
+                     <i>file_name</i><b>.pag</b>  and  <i>file_name</i><b>.dir</b>.   This is
+                     available only on systems with  support  for
                      <b>dbm</b> databases.
 
-              <b>hash</b>   The output file  is  a  hashed  file,  named
-                     <i>file_name</i><b>.db</b>.   This  is  available  only on
+              <b>hash</b>   The  output  file  is  a  hashed file, named
+                     <i>file_name</i><b>.db</b>.  This  is  available  only  on
                      systems with support for <b>db</b> databases.
 
-              When no <i>file_type</i> is specified, the  software  uses
-              the  database  type specified via the <b>database</b><i>_</i><b>type</b>
+              When  no  <i>file_type</i> is specified, the software uses
+              the database type specified via  the  <b>database</b><i>_</i><b>type</b>
               configuration parameter.
 
        <i>file_name</i>
-              The name of  the  lookup  table  source  file  when
+              The  name  of  the  lookup  table  source file when
               rebuilding a database.
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to the standard error
        stream. No output means no problems. Duplicate entries are
-       skipped and are flagged with a warning.
-
-
 
 
 
@@ -137,8 +137,10 @@ POSTMAP(1)                                             POSTMAP(1)
 POSTMAP(1)                                             POSTMAP(1)
 
 
+       skipped and are flagged with a warning.
+
 <b>BUGS</b>
-       The  "delete  key" support is limited to one delete opera-
+       The "delete key" support is limited to one  delete  opera-
        tion per command invocation.
 
 <b>ENVIRONMENT</b>
@@ -150,12 +152,12 @@ POSTMAP(1)                                             POSTMAP(1)
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
        <b>database</b><i>_</i><b>type</b>
-              Default output database type.  On  many  UNIX  sys-
-              tems,  the  default database type is either <b>hash</b> or
+              Default  output  database  type.  On many UNIX sys-
+              tems, the default database type is either  <b>hash</b>  or
               <b>dbm</b>.
 
 <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>
@@ -189,8 +191,6 @@ POSTMAP(1)                                             POSTMAP(1)
 
 
 
-
-
 
 
 
index 17a2385a4479dd70ae7b1a3c0e7f47348b733543..9b760ccd327e7f4e3afaa972dee331864871831d 100644 (file)
@@ -122,7 +122,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
 
             <b>.foo.org</b>      <b>error:mail</b> <b>for</b> <b>*.foo.org</b> <b>is</b> <b>not</b> <b>deliverable</b>
 
-       This causes all mail for <i>user</i>@<i>anything</i><b>foo.org</b>
+       This causes all mail for <i>user</i>@<i>anything</i><b>.foo.org</b>
        to be bounced.
 
 
index 23514312501fd35d391598344592fae64b975175..44368bbd1a69b1c0562649b0df32dfcb83b1b2ab 100644 (file)
@@ -4,7 +4,8 @@ SHELL   = /bin/sh
 
 DAEMONS        = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
        man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
-       man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8
+       man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
+       man8/nqmgr.8
 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
        man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
@@ -46,6 +47,10 @@ man8/lmtp.8: ../lmtp/lmtp.c
 man8/master.8: ../master/master.c
        ../mantools/srctoman $? >$@
 
+man8/nqmgr.8: ../nqmgr/qmgr.c
+       ../mantools/srctoman $? | \
+               sed -e 's/qmgr[^_]/n&/' -e 's/QMGR[^_]/N&/' >$@
+
 man8/pickup.8: ../pickup/pickup.c
        ../mantools/srctoman $? >$@
 
index a2b3e652ecc6dad73b23a2b0abba0bf83f6dec52..88bc2242cc07062a68a1ea266562ced9e41f8d21 100644 (file)
@@ -9,7 +9,7 @@ Postfix alias database maintenance
 .na
 .nf
 .fi
-\fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
+\fBpostalias\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR]
 [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
 [\fIfile_type\fR:]\fIfile_name\fR ...
 .SH DESCRIPTION
@@ -48,6 +48,9 @@ the host operating system.
 Search the specified maps for \fIkey\fR and print the first value
 found on the standard output stream. The exit status is non-zero
 if the requested information was not found.
+.IP \fB-r\fR
+When updating a table, do not warn about duplicate entries; silently
+replace them.
 .IP \fB-v\fR
 Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 options make the software increasingly verbose.
index 1db5db8ac51cc265bfc5603a156fd4e135f889fd..384d624fb24a12e93f79ec76fa4432be4855fb81 100644 (file)
@@ -9,7 +9,7 @@ Postfix lookup table management
 .na
 .nf
 .fi
-\fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR]
+\fBpostmap\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR]
 [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
 .SH DESCRIPTION
 .ad
@@ -66,6 +66,9 @@ the host operating system.
 Search the specified maps for \fIkey\fR and print the first value
 found on the standard output stream. The exit status is non-zero
 if the requested information was not found.
+.IP \fB-r\fR
+When updating a table, do not warn about duplicate entries; silently
+replace them.
 .IP \fB-v\fR
 Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 options make the software increasingly verbose.
index 762bd8097120840ae6f2ff1f163435703800e342..12fa3c2736b7dc4c79d0fe63bab51a438ba87473 100644 (file)
@@ -115,7 +115,7 @@ The error mailer can be used to bounce mail:
 .ti +5
 \fB\&.foo.org      error:mail for *.foo.org is not deliverable\fR
 
-This causes all mail for \fIuser\fR@\fIanything\fBfoo.org\fR
+This causes all mail for \fIuser\fR@\fIanything\fB.foo.org\fR
 to be bounced.
 .SH REGULAR EXPRESSION TABLES
 .na
diff --git a/postfix/man/man8/nqmgr.8 b/postfix/man/man8/nqmgr.8
new file mode 100644 (file)
index 0000000..e66ad52
--- /dev/null
@@ -0,0 +1,302 @@
+.TH NQMGR 8 
+.ad
+.fi
+.SH NAME
+qmgr
+\-
+Postfix queue manager
+.SH SYNOPSIS
+.na
+.nf
+\fBnqmgr\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The \fBnqmgr\fR daemon awaits the arrival of incoming mail
+and arranges for its delivery via Postfix delivery processes.
+The actual mail routing strategy is delegated to the
+\fBtrivial-rewrite\fR(8) daemon.
+This program expects to be run from the \fBmaster\fR(8) process
+manager.
+
+Mail addressed to the local \fBdouble-bounce\fR address is silently
+discarded.  This stops potential loops caused by undeliverable
+bounce notifications.
+
+Mail addressed to a user listed in the optional \fBrelocated\fR
+database is bounced with a "user has moved to \fInew_location\fR"
+message. See \fBrelocated\fR(5) for a precise description.
+.SH MAIL QUEUES
+.na
+.nf
+.ad
+.fi
+The \fBnqmgr\fR daemon maintains the following queues:
+.IP \fBincoming\fR
+Inbound mail from the network, or mail picked up by the
+local \fBpickup\fR agent from the \fBmaildrop\fR directory.
+.IP \fBactive\fR
+Messages that the queue manager has opened for delivery. Only
+a limited number of messages is allowed to enter the \fBactive\fR
+queue (leaky bucket strategy, for a fixed delivery rate).
+.IP \fBdeferred\fR
+Mail that could not be delivered upon the first attempt. The queue
+manager implements exponential backoff by doubling the time between
+delivery attempts.
+.IP \fBcorrupt\fR
+Unreadable or damaged queue files are moved here for inspection.
+.SH DELIVERY STATUS REPORTS
+.na
+.nf
+.ad
+.fi
+The \fBnqmgr\fR daemon keeps an eye on per-message delivery status
+reports in the following directories. Each status report file has
+the same name as the corresponding message file:
+.IP \fBbounce\fR
+Per-recipient status information about why mail is bounced.
+These files are maintained by the \fBbounce\fR(8) daemon.
+.IP \fBdefer\fR
+Per-recipient status information about why mail is delayed.
+These files are maintained by the \fBdefer\fR(8) daemon.
+.PP
+The \fBnqmgr\fR daemon is responsible for asking the
+\fBbounce\fR(8) or \fBdefer\fR(8) daemons to send non-delivery
+reports.
+.SH STRATEGIES
+.na
+.nf
+.ad
+.fi
+The queue manager implements a variety of strategies for
+either opening queue files (input) or for message delivery (output).
+.IP "\fBleaky bucket\fR"
+This strategy limits the number of messages in the \fBactive\fR queue
+and prevents the queue manager from running out of memory under
+heavy load.
+.IP \fBfairness\fR
+When the \fBactive\fR queue has room, the queue manager takes one
+message from the \fBincoming\fR queue and one from the \fBdeferred\fR
+queue. This prevents a large mail backlog from blocking the delivery
+of new mail.
+.IP "\fBslow start\fR"
+This strategy eliminates "thundering herd" problems by slowly
+adjusting the number of parallel deliveries to the same destination.
+.IP "\fBround robin\fR
+The queue manager sorts delivery requests by destination.
+Round-robin selection prevents one destination from dominating
+deliveries to other destinations.
+.IP "\fBexponential backoff\fR"
+Mail that cannot be delivered upon the first attempt is deferred.
+The time interval between delivery attempts is doubled after each
+attempt.
+.IP "\fBdestination status cache\fR"
+The queue manager avoids unnecessary delivery attempts by
+maintaining a short-term, in-memory list of unreachable destinations.
+.IP "\fBpreemptive message scheduling\fR"
+The queue manager attempts to minimize the average per-recipient delay
+while still preserving the correct per-message delays, using
+a sophisticated preemptive message scheduling.
+.SH TRIGGERS
+.na
+.nf
+.ad
+.fi
+On an idle system, the queue manager waits for the arrival of
+trigger events, or it waits for a timer to go off. A trigger
+is a one-byte message.
+Depending on the message received, the queue manager performs
+one of the following actions (the message is followed by the
+symbolic constant used internally by the software):
+.IP "\fBD (QMGR_REQ_SCAN_DEFERRED)\fR"
+Start a deferred queue scan.  If a deferred queue scan is already
+in progress, that scan will be restarted as soon as it finishes.
+.IP "\fBI (QMGR_REQ_SCAN_INCOMING)\fR"
+Start an incoming queue scan. If an incoming queue scan is already
+in progress, that scan will be restarted as soon as it finishes.
+.IP "\fBA (QMGR_REQ_SCAN_ALL)\fR"
+Ignore deferred queue file time stamps. The request affects
+the next deferred queue scan.
+.IP "\fBF (QMGR_REQ_FLUSH_DEAD)\fR"
+Purge all information about dead transports and destinations.
+.IP "\fBW (TRIGGER_REQ_WAKEUP)\fR"
+Wakeup call, This is used by the master server to instantiate
+servers that should not go away forever. The action is to start
+an incoming queue scan.
+.PP
+The \fBnqmgr\fR daemon reads an entire buffer worth of triggers.
+Multiple identical trigger requests are collapsed into one, and
+trigger requests are sorted so that \fBA\fR and \fBF\fR precede
+\fBD\fR and \fBI\fR. Thus, in order to force a deferred queue run,
+one would request \fBA F D\fR; in order to notify the queue manager
+of the arrival of new mail one would request \fBI\fR.
+.SH STANDARDS
+.na
+.nf
+.ad
+.fi
+None. The \fBnqmgr\fR daemon does not interact with the outside world.
+.SH SECURITY
+.na
+.nf
+.ad
+.fi
+The \fBnqmgr\fR daemon is not security sensitive. It reads
+single-character messages from untrusted local users, and thus may
+be susceptible to denial of service attacks. The \fBnqmgr\fR daemon
+does not talk to the outside world, and it can be run at fixed low
+privilege in a chrooted environment.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to the syslog daemon.
+Corrupted message files are saved to the \fBcorrupt\fR queue
+for further inspection.
+
+Depending on the setting of the \fBnotify_classes\fR parameter,
+the postmaster is notified of bounces and of other trouble.
+.SH BUGS
+.ad
+.fi
+A single queue manager process has to compete for disk access with
+multiple front-end processes such as \fBsmtpd\fR. A sudden burst of
+inbound mail can negatively impact outbound delivery rates.
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.ad
+.fi
+The following \fBmain.cf\fR parameters are especially relevant to
+this program. See the Postfix \fBmain.cf\fR file for syntax details
+and for default values. Use the \fBpostfix reload\fR command after
+a configuration change.
+.SH Miscellaneous
+.ad
+.fi
+.IP \fBallow_min_user\fR
+Do not bounce recipient addresses that begin with '-'.
+.IP \fBrelocated_maps\fR
+Tables with contact information for users, hosts or domains
+that no longer exist. See \fBrelocated\fR(5).
+.IP \fBqueue_directory\fR
+Top-level directory of the Postfix queue.
+.SH "Active queue controls"
+.ad
+.fi
+In the text below, \fItransport\fR is the first field in a
+\fBmaster.cf\fR entry.
+.IP \fBqmgr_message_active_limit\fR
+Limit the number of messages in the active queue.
+.IP \fBqmgr_message_recipient_limit\fR
+Limit the number of in-memory recipients.
+.sp
+This parameter also limits the size of the short-term, in-memory
+destination cache.
+.IP \fBqmgr_message_recipient_minimum\fR
+Per message minimum of in-memory recipients.
+.IP \fBdefault_recipient_limit\fR
+Default limit on the number of in-memory recipients per transport.
+.IP \fItransport\fB_recipient_limit\fR
+Limit on the number of in-memory recipients, for the named
+message \fItransport\fR.
+.IP \fBdefault_extra_recipient_limit\fR
+Default limit on the total number of per transport in-memory
+recipients that the preempting messages can have.
+.IP \fItransport\fB_extra_recipient_limit\fR
+Limit on the number of in-memory recipients which all preempting
+messages delivered by the transport \fItransport\fR can have.
+.SH "Timing controls"
+.ad
+.fi
+.IP \fBmin_backoff\fR
+Minimal time in seconds between delivery attempts
+of a deferred message.
+.sp
+This parameter also limits the time an unreachable destination
+is kept in the short-term, in-memory destination status cache.
+.IP \fBmax_backoff\fR
+Maximal time in seconds between delivery attempts
+of a deferred message.
+.IP \fBmaximal_queue_lifetime\fR
+Maximal time in days a message is queued
+before it is sent back as undeliverable.
+.IP \fBqueue_run_delay\fR
+Time in seconds between deferred queue scans. Queue scans do
+not overlap.
+.IP \fBtransport_retry_time\fR
+Time in seconds between attempts to contact a broken
+delivery transport.
+.SH "Concurrency controls"
+.ad
+.fi
+.IP \fBinitial_destination_concurrency\fR
+Initial per-destination concurrency level for parallel delivery
+to the same destination.
+.IP \fBdefault_destination_concurrency_limit\fR
+Default limit on the number of parallel deliveries to the same
+destination.
+.IP \fItransport\fB_destination_concurrency_limit\fR
+Limit on the number of parallel deliveries to the same destination,
+for delivery via the named message \fItransport\fR.
+.SH "Recipient controls"
+.ad
+.fi
+.IP \fBdefault_destination_recipient_limit\fR
+Default limit on the number of recipients per message transfer.
+.IP \fItransport\fB_destination_recipient_limit\fR
+Limit on the number of recipients per message transfer, for the
+named message \fItransport\fR.
+.SH "Message scheduling"
+.ad
+.fi
+.IP "\fItransport\fB_delivery_slot_cost\fR (valid range: 0,2,3...)
+This parameter basically controls how often a message
+delivered by \fItransport\fB can be preempted by another
+message.
+An internal per-message/transport counter is incremented by one
+for each \fItransport\fB_delivery_slot_cost\fR
+deliveries handled by \fItransport\fR. This counter represents
+the number of "available delivery slots" for use by other messages.
+Current message can be preempted by another message when that
+other message can be delivered using less \fItranpsort\fR agents
+than the value of the "available delivery slots" counter.
+.sp
+Value equal to 0 disables the message preemption for \fItransport\fR.
+.IP \fItransport\fB_minimum_delivery_slots\fR
+Message preemption is not attempted at all whenever a message
+that can't ever accumulate at least \fItransport\fB_minimum_delivery_slots\fR
+available delivery slots is being delivered by \fItransport\fR.
+.IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)"
+.IP \fItransport\fB_delivery_slot_loan\fR
+These parameters speed up the moment when a message preemption can happen.
+Instead of waiting until the full amount of delivery slots
+required is available, the preemption can happen when
+\fItransport\fB_delivery_slot_discount\fR percent of the required
+amount plus \fItransport\fB_delivery_slot_loan\fR still remains to
+be accumulated. Note that the full amount will still have to be
+accumulated before another preemption can take place later.
+.IP \fBdefault_delivery_slot_cost\fR
+.IP \fBdefault_minimum_delivery_slots\fR
+.IP \fBdefault_delivery_slot_discount\fR
+.IP \fBdefault_delivery_slot_loan\fR
+Default values for the transport specific parameters described above.
+.SH SEE ALSO
+.na
+.nf
+master(8), process manager
+relocated(5), format of the "user has moved" table
+syslogd(8) system logging
+trivial-rewrite(8), address routing
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index aff5a8bd90c4dafd7ece8265d2b0f09eee0d0bf2..74acca9e1f056ba5e841267de9769a41512a08b4 100644 (file)
@@ -83,8 +83,8 @@
 /*     maintaining a short-term, in-memory list of unreachable destinations.
 /* .IP "\fBpreemptive message scheduling\fR"
 /*     The queue manager attempts to minimize the average per-recipient delay
-/*     while still assuring equality of average per-message delays, using
-/*     sophisticated preemptive message scheduling.
+/*     while still preserving the correct per-message delays, using
+/*     sophisticated preemptive message scheduling.
 /* TRIGGERS
 /* .ad
 /* .fi
 /*     recipients that the preempting messages can have.
 /* .IP \fItransport\fB_extra_recipient_limit\fR
 /*     Limit on the number of in-memory recipients which all preempting
-/*     messages delivered by transport \fItransport\fR can have.
+/*     messages delivered by the transport \fItransport\fR can have.
 /* .SH "Timing controls"
 /* .ad
 /* .fi
 /* .IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)"
 /* .IP \fItransport\fB_delivery_slot_loan\fR
 /*     These parameters speed up the moment when a message preemption can happen.
-/*     Instead of waiting till the full amount of delivery slots
+/*     Instead of waiting until the full amount of delivery slots
 /*     required is available, the preemption can happen when
 /*     \fItransport\fB_delivery_slot_discount\fR percent of the required
 /*     amount plus \fItransport\fB_delivery_slot_loan\fR still remains to
@@ -327,9 +327,6 @@ char   *var_relocated_maps;
 char   *var_virtual_maps;
 char   *var_defer_xports;
 bool    var_allow_min_user;
-int     var_qmgr_hog;                   /* XXX */
-int     var_qmgr_fudge;                 /* XXX */
-int     var_local_rcpt_lim;            /* XXX */
 
 static QMGR_SCAN *qmgr_incoming;
 static QMGR_SCAN *qmgr_deferred;
@@ -435,9 +432,8 @@ static int qmgr_loop(char *unused_name, char **unused_argv)
 
     /*
      * Let some new blood into the active queue when the queue size is
-     * smaller than some configurable limit, and when the number of in-core
-     * recipients does not exceed some configurable limit. When the system is
-     * under heavy load, favor new mail over old mail.
+     * smaller than some configurable limit. When the system is under heavy
+     * load, favor new mail over old mail.
      */
     if (qmgr_message_count < var_qmgr_active_limit)
        if ((in_path = qmgr_scan_next(qmgr_incoming)) != 0)
@@ -513,7 +509,7 @@ int     main(int argc, char **argv)
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
-       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 0,
+       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 1000,
        VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0,
        VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 0, 0,
        VAR_QMGR_MSG_RCPT_LIMIT, DEF_QMGR_MSG_RCPT_LIMIT, &var_qmgr_msg_rcpt_limit, 1, 0,
@@ -527,9 +523,6 @@ int     main(int argc, char **argv)
        VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
        VAR_DEST_CON_LIMIT, DEF_DEST_CON_LIMIT, &var_dest_con_limit, 0, 0,
        VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0,
-       VAR_QMGR_HOG, DEF_QMGR_HOG, &var_qmgr_hog, 10, 100,
-       VAR_QMGR_FUDGE, DEF_QMGR_FUDGE, &var_qmgr_fudge, 10, 100,
-       VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index a47db71fdeae84dca65cedf8191feb1a8555e6e6..5982b4f604d9e50eda0b16431dbff8d085d081bc 100644 (file)
@@ -28,7 +28,7 @@ typedef struct QMGR_QUEUE QMGR_QUEUE;
 typedef struct QMGR_ENTRY QMGR_ENTRY;
 typedef struct QMGR_MESSAGE QMGR_MESSAGE;
 typedef struct QMGR_JOB QMGR_JOB;
-typedef struct QMGR_PEER QMGR_PEER ;
+typedef struct QMGR_PEER QMGR_PEER;
 typedef struct QMGR_TRANSPORT_LIST QMGR_TRANSPORT_LIST;
 typedef struct QMGR_QUEUE_LIST QMGR_QUEUE_LIST;
 typedef struct QMGR_ENTRY_LIST QMGR_ENTRY_LIST;
@@ -121,20 +121,27 @@ struct QMGR_TRANSPORT {
     int     dest_concurrency_limit;    /* concurrency per domain */
     int     init_dest_concurrency;     /* init. per-domain concurrency */
     int     recipient_limit;           /* recipients per transaction */
-    int     rcpt_per_stack;             /* slots reserved for job on 1st stack level */
-    int     rcpt_unused;                /* available in-core slots */
-    int     slot_cost;                  /* cost of new preemption slot (# selected entries) */
-    int     slot_loan;                  /* preemption boost offset and factor, see */
-    int     slot_loan_factor;           /* qmgr_job_preempt() for more info */
-    int     min_slots;                  /* when preemption can take effect at all */
+    int     rcpt_per_stack;            /* extra slots reserved for jobs on
+                                        * the job stack */
+    int     rcpt_unused;               /* available in-core recipient slots */
+    int     slot_cost;                 /* cost of new preemption slot (#
+                                        * selected entries) */
+    int     slot_loan;                 /* preemption boost offset and
+                                        * factor, see */
+    int     slot_loan_factor;          /* qmgr_job_preempt() for more info */
+    int     min_slots;                 /* when preemption can take effect at
+                                        * all */
     struct HTABLE *queue_byname;       /* queues indexed by domain */
     QMGR_QUEUE_LIST queue_list;                /* queues, round robin order */
-    struct HTABLE  *job_byname;         /* jobs indexed by queue id */
-    QMGR_JOB_LIST   job_list;           /* list of message jobs (1 per message) */
-    QMGR_JOB_LIST   job_stack;          /* job stack for tracking preemption */
-    QMGR_JOB *job_next_unread;          /* next job with unread recipients */
-    QMGR_JOB *candidate_cache;         /* cached result from qmgr_job_candidate() */
-    time_t    candidate_cache_time;    /* when candidate_cache was last updated */
+    struct HTABLE *job_byname;         /* jobs indexed by queue id */
+    QMGR_JOB_LIST job_list;            /* list of message jobs (1 per
+                                        * message) */
+    QMGR_JOB_LIST job_stack;           /* job stack for tracking preemption */
+    QMGR_JOB *job_next_unread;         /* next job with unread recipients */
+    QMGR_JOB *candidate_cache;         /* cached result from
+                                        * qmgr_job_candidate() */
+    time_t  candidate_cache_time;      /* when candidate_cache was last
+                                        * updated */
     QMGR_TRANSPORT_LIST peers;         /* linkage */
     char   *reason;                    /* why unavailable */
 };
@@ -217,7 +224,7 @@ struct QMGR_ENTRY {
     QMGR_MESSAGE *message;             /* message info */
     QMGR_RCPT_LIST rcpt_list;          /* as many as it takes */
     QMGR_QUEUE *queue;                 /* parent linkage */
-    QMGR_PEER  *peer;                  /* parent linkage */
+    QMGR_PEER *peer;                   /* parent linkage */
     QMGR_ENTRY_LIST queue_peers;       /* per queue neighbor entries */
     QMGR_ENTRY_LIST peer_peers;                /* per peer neighbor entries */
 };
@@ -240,7 +247,8 @@ struct QMGR_MESSAGE {
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
     long    arrival_time;              /* time when queued */
-    time_t  queued_time;               /* time when moved to the active queue */
+    time_t  queued_time;               /* time when moved to the active
+                                        * queue */
     long    warn_offset;               /* warning bounce flag offset */
     time_t  warn_time;                 /* time next warning to be sent */
     long    data_offset;               /* data seek offset */
@@ -254,10 +262,11 @@ struct QMGR_MESSAGE {
     long    rcpt_offset;               /* more recipients here */
     long    unread_offset;             /* more unread recipients here */
     QMGR_RCPT_LIST rcpt_list;          /* complete addresses */
-    int     rcpt_count;                 /* used recipient slots */
-    int     rcpt_limit;                 /* maximum read in-core */
-    int     rcpt_unread;                /* # of recipients left in queue file */
-    QMGR_JOB_LIST  job_list;            /* jobs delivering this message (1 per transport) */
+    int     rcpt_count;                        /* used recipient slots */
+    int     rcpt_limit;                        /* maximum read in-core */
+    int     rcpt_unread;               /* # of recipients left in queue file */
+    QMGR_JOB_LIST job_list;            /* jobs delivering this message (1
+                                        * per transport) */
 };
 
 #define QMGR_MESSAGE_LOCKED    ((QMGR_MESSAGE *) 1)
@@ -274,39 +283,44 @@ extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
 
  /*
   * Sometimes it's required to access the transport queues and entries on per
-  * message basis. That's what the QMGR_JOB structure is for - it groups all per
-  * message information within each transport using a list of QMGR_PEER structures.
-  * These structures in turn correspond with per message QMGR_QUEUE structure
-  * and list all per message QMGR_ENTRY structures.
+  * message basis. That's what the QMGR_JOB structure is for - it groups all
+  * per message information within each transport using a list of QMGR_PEER
+  * structures. These structures in turn correspond with per message
+  * QMGR_QUEUE structure and list all per message QMGR_ENTRY structures.
   */
 struct QMGR_PEER_LIST {
-    QMGR_PEER  *next;
-    QMGR_PEER  *prev;
+    QMGR_PEER *next;
+    QMGR_PEER *prev;
 };
 
 struct QMGR_JOB {
-    QMGR_MESSAGE   *message;            /* message delivered by this job */
-    QMGR_TRANSPORT *transport;          /* transport this job belongs to */
-    QMGR_JOB_LIST   message_peers;      /* per message neighbor linkage */
-    QMGR_JOB_LIST   transport_peers;    /* per transport neighbor linkage */
-    QMGR_JOB_LIST   stack_peers;        /* transport stack linkage */
-    int             stack_level;        /* job stack nesting level (-1 -> retired) */
-    struct HTABLE  *peer_byname;        /* message job peers, indexed by domain */
-    QMGR_PEER_LIST  peer_list;          /* list of message job peers */
-    int             slots_used;         /* slots used during preemption */
-    int             slots_available;    /* slots available for preemption (* slot_cost) */
-    int             selected_entries;   /* # of entries selected for delivery so far */
-    int             read_entries;       /* # of entries read in-core so far */
-    int             rcpt_count;         /* used recipient slots */
-    int             rcpt_limit;         /* available recipient slots */
+    QMGR_MESSAGE *message;             /* message delivered by this job */
+    QMGR_TRANSPORT *transport;         /* transport this job belongs to */
+    QMGR_JOB_LIST message_peers;       /* per message neighbor linkage */
+    QMGR_JOB_LIST transport_peers;     /* per transport neighbor linkage */
+    QMGR_JOB_LIST stack_peers;         /* transport stack linkage */
+    int     stack_level;               /* job stack nesting level (-1 ->
+                                        * retired) */
+    struct HTABLE *peer_byname;                /* message job peers, indexed by
+                                        * domain */
+    QMGR_PEER_LIST peer_list;          /* list of message job peers */
+    int     slots_used;                        /* slots used during preemption */
+    int     slots_available;           /* slots available for preemption (*
+                                        * slot_cost) */
+    int     selected_entries;          /* # of entries selected for delivery
+                                        * so far */
+    int     read_entries;              /* # of entries read in-core so far */
+    int     rcpt_count;                        /* used recipient slots */
+    int     rcpt_limit;                        /* available recipient slots */
 };
 
 struct QMGR_PEER {
-    QMGR_JOB       *job;                /* job handling this peer */
-    QMGR_QUEUE     *queue;              /* queue corresponding with this peer */
-    int             refcount;           /* peer entries */
-    QMGR_ENTRY_LIST entry_list;         /* todo message entries queued for this peer */
-    QMGR_PEER_LIST  peers;              /* neighbor linkage */
+    QMGR_JOB *job;                     /* job handling this peer */
+    QMGR_QUEUE *queue;                 /* queue corresponding with this peer */
+    int     refcount;                  /* peer entries */
+    QMGR_ENTRY_LIST entry_list;                /* todo message entries queued for
+                                        * this peer */
+    QMGR_PEER_LIST peers;              /* neighbor linkage */
 };
 
 extern QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *);
index 57b4631ecadc9068b0deb8d6945651c1ca83a00f..9df7e74d8fde38886ff9818d3e0d233abce30beb 100644 (file)
 
 /* qmgr_entry_select - select queue entry for delivery */
 
-QMGR_ENTRY *qmgr_entry_select(QMGR_PEER *peer)
+QMGR_ENTRY *qmgr_entry_select(QMGR_PEER * peer)
 {
     QMGR_ENTRY *entry;
     QMGR_QUEUE *queue;
 
     if ((entry = peer->entry_list.next) != 0) {
-        queue = entry->queue;
+       queue = entry->queue;
        QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers);
        queue->todo_refcount--;
        QMGR_LIST_APPEND(queue->busy, entry, queue_peers);
        queue->busy_refcount++;
        QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers);
-        peer->job->selected_entries++;
+       peer->job->selected_entries++;
     }
     return (entry);
 }
@@ -133,7 +133,8 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
     QMGR_QUEUE *queue = entry->queue;
     QMGR_MESSAGE *message = entry->message;
     QMGR_PEER *peer = entry->peer;
-    QMGR_JOB *sponsor, *job = peer->job;
+    QMGR_JOB *sponsor,
+           *job = peer->job;
 
     /*
      * Take this entry off the in-core queue.
@@ -145,6 +146,7 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
        queue->busy_refcount--;
     } else if (which == QMGR_QUEUE_TODO) {
        QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers);
+       job->selected_entries++;
        QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers);
        queue->todo_refcount--;
     } else {
@@ -162,27 +164,28 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
     myfree((char *) entry);
 
     /*
-     * Make sure that transport of any retired or finishing jobs that
-     * donated recipient slots to this job's message gets them back first.
-     * Then, if possible, pass the remaining unused recipient slots to the
-     * next job in the queue.
+     * Make sure that the transport of any retired or finishing job that
+     * donated recipient slots to this message gets them back first. Then, if
+     * possible, pass the remaining unused recipient slots to the next job in
+     * the job list.
      */
     for (sponsor = message->job_list.next; sponsor; sponsor = sponsor->message_peers.next) {
-        if (sponsor->rcpt_count >= sponsor->rcpt_limit || sponsor == job)
-            continue;
-        if (sponsor->stack_level < 0 || message->rcpt_offset == 0)
-            qmgr_job_move_limits(sponsor);
+       if (sponsor->rcpt_count >= sponsor->rcpt_limit || sponsor == job)
+           continue;
+       if (sponsor->stack_level < 0 || message->rcpt_offset == 0)
+           qmgr_job_move_limits(sponsor);
     }
     if (message->rcpt_offset == 0) {
-        qmgr_job_move_limits(job);
+       qmgr_job_move_limits(job);
     }
+
     /*
-     * When there are no more entries for this peer, discard the peer structure.
+     * When there are no more entries for this peer, discard the peer
+     * structure.
      */
-   peer->refcount--;
-   if (peer->refcount == 0)
-       qmgr_peer_free(peer);
+    peer->refcount--;
+    if (peer->refcount == 0)
+       qmgr_peer_free(peer);
 
     /*
      * When the in-core queue for this site is empty and when this site is
@@ -208,7 +211,7 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
 
 /* qmgr_entry_create - create queue todo entry */
 
-QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
+QMGR_ENTRY *qmgr_entry_create(QMGR_PEER * peer, QMGR_MESSAGE *message)
 {
     QMGR_ENTRY *entry;
     QMGR_QUEUE *queue = peer->queue;
@@ -226,7 +229,7 @@ QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
     message->refcount++;
     entry->peer = peer;
     QMGR_LIST_APPEND(peer->entry_list, entry, peer_peers);
-    peer->refcount++ ;
+    peer->refcount++;
     entry->queue = queue;
     QMGR_LIST_APPEND(queue->todo, entry, queue_peers);
     queue->todo_refcount++;
index 46bb8ee5d9c0df6571dbaf908a78eca56bab6b94..d13c949124ff74894eb8fd8c091fb850a8efda76 100644 (file)
@@ -26,8 +26,8 @@
 /*
 /*     qmgr_job_obtain() finds an existing job for named message and
 /*     transport combination. New empty job is created if no existing can
-/*     be found.In either case, the job is prepared for assignement of
-/*     (more) message recipients
+/*     be found. In either case, the job is prepared for assignement of
+/*     (more) message recipients.
 /*
 /*     qmgr_job_free() disposes of a per-transport job after all
 /*     its entries have been taken care of. It is an error to dispose
@@ -93,7 +93,7 @@ static void qmgr_job_pop(QMGR_JOB *);
 static QMGR_JOB *qmgr_job_create(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
 {
     QMGR_JOB *job;
-    
+
     job = (QMGR_JOB *) mymalloc(sizeof(QMGR_JOB));
     job->message = message;
     QMGR_LIST_APPEND(message->job_list, job, message_peers);
@@ -114,75 +114,78 @@ static QMGR_JOB *qmgr_job_create(QMGR_MESSAGE *message, QMGR_TRANSPORT *transpor
 
 /* qmgr_job_link - append the job to the job list, according to the time it was queued */
 
-static void qmgr_job_link(QMGR_JOB *job)
+static void qmgr_job_link(QMGR_JOB * job)
 {
     QMGR_TRANSPORT *transport = job->transport;
     QMGR_MESSAGE *message = job->message;
-    QMGR_JOB *prev,*next,*unread;
-    int delay;
-    
+    QMGR_JOB *prev,
+           *next,
+           *unread;
+    int     delay;
+
     unread = transport->job_next_unread;
-    
+
     /*
      * This may look inefficient but under normal operation it is expected
-     * that the loop will stop right away, resulting in normal list append below.
-     * However, this code is necessary for reviving retired jobs and for jobs
-     * which are created long after the first chunk of recipients was read in-core
-     * (either of these can happen only for multi-transport messages).
-     *
-     * In case this is found unsatisfactory one day, it's possible to deploy some
-     * smarter technique (using some form of lookup trees perhaps).
+     * that the loop will stop right away, resulting in normal list append
+     * below. However, this code is necessary for reviving retired jobs and
+     * for jobs which are created long after the first chunk of recipients
+     * was read in-core (either of these can happen only for multi-transport
+     * messages).
+     * 
+     * In case this is found unsatisfactory one day, it's possible to deploy
+     * some smarter technique (using some form of lookup trees perhaps).
      */
     for (next = 0, prev = transport->job_list.prev; prev;
-                        next = prev, prev = prev->transport_peers.prev)
-    {
-        delay = message->queued_time - prev->message->queued_time;
-        if (delay >= 0)
-            break;
-        if (unread == prev)
-            unread = 0;
+        next = prev, prev = prev->transport_peers.prev) {
+       delay = message->queued_time - prev->message->queued_time;
+       if (delay >= 0)
+           break;
+       if (unread == prev)
+           unread = 0;
     }
-    
+
     /*
-     * Don't link the new job in front of the first job on the job list
-     * if that job was already used for the regular delivery. 
-     * This seems like a subtle difference but it helps many invariants
-     * used at various other places to remain true.
+     * Don't link the new job in front of the first job on the job list if
+     * that job was already used for the regular delivery. This seems like a
+     * subtle difference but it helps many invariants used at various other
+     * places to remain true.
      */
     if (prev == 0 && next != 0 && next->slots_used != 0) {
-        prev = next;
-        next = next->transport_peers.next;
-        /*
-         * The following is not currently necessary but is done anyway
-         * for the sake of consistency.
-         */
-        if (prev == transport->job_next_unread)
-            unread = prev;
+       prev = next;
+       next = next->transport_peers.next;
+
+       /*
+        * The following is not currently necessary but is done anyway for
+        * the sake of consistency.
+        */
+       if (prev == transport->job_next_unread)
+           unread = prev;
     }
-    
+
     /*
      * Link the job into the proper place on the job list.
      */
     job->transport_peers.prev = prev;
     job->transport_peers.next = next;
     if (prev != 0)
-        prev->transport_peers.next = job;
+       prev->transport_peers.next = job;
     else
-        transport->job_list.next = job;
+       transport->job_list.next = job;
     if (next != 0)
-        next->transport_peers.prev = job;
+       next->transport_peers.prev = job;
     else
-        transport->job_list.prev = job;
+       transport->job_list.prev = job;
 
     /*
-     * Update the pointer to the first unread job on the job list
-     * and steal the unused recipient slots from the old one.
+     * Update the pointer to the first unread job on the job list and steal
+     * the unused recipient slots from the old one.
      */
     if (unread == 0) {
-        unread = transport->job_next_unread;
-        transport->job_next_unread = job;
-        if (unread != 0)
-            qmgr_job_move_limits(unread);
+       unread = transport->job_next_unread;
+       transport->job_next_unread = job;
+       if (unread != 0)
+           qmgr_job_move_limits(unread);
     }
 
     /*
@@ -191,9 +194,9 @@ static void qmgr_job_link(QMGR_JOB *job)
      * (which is usually after all recipients have been read in core).
      */
     if (transport->rcpt_unused > 0) {
-        job->rcpt_limit += transport->rcpt_unused;
-        message->rcpt_limit += transport->rcpt_unused;
-        transport->rcpt_unused = 0;
+       job->rcpt_limit += transport->rcpt_unused;
+       message->rcpt_limit += transport->rcpt_unused;
+       transport->rcpt_unused = 0;
     }
 }
 
@@ -201,61 +204,63 @@ static void qmgr_job_link(QMGR_JOB *job)
 
 static QMGR_JOB *qmgr_job_find(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
 {
+
     /*
-     * Instead of traversing the message job list, we use single per transport
-     * hash table. This is better (at least with respect to memory usage)
-     * than having single hash table (usually almost empty) for each message.
+     * Instead of traversing the message job list, we use single per
+     * transport hash table. This is better (at least with respect to memory
+     * usage) than having single hash table (usually almost empty) for each
+     * message.
      */
     return ((QMGR_JOB *) htable_find(transport->job_byname, message->queue_id));
 }
 
 /* qmgr_job_obtain - find/create the appropriate job and make it ready for new recipients */
 
-QMGR_JOB * qmgr_job_obtain(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
+QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
 {
     QMGR_JOB *job;
-    
+
     /*
-     * Try finding the existing job and revive it if it was already retired.
-     * Create the new job for this transport/message combination otherwise.
+     * Try finding an existing job and revive it if it was already retired.
+     * Create a new job for this transport/message combination otherwise.
      */
     if ((job = qmgr_job_find(message, transport)) != 0) {
-        if (job->stack_level < 0) {
-            job->stack_level = 0;
-            qmgr_job_link(job);
-        }
-    }
-    else {
-        job = qmgr_job_create(message, transport);
-        qmgr_job_link(job);
+       if (job->stack_level < 0) {
+           job->stack_level = 0;
+           qmgr_job_link(job);
+       }
+    } else {
+       job = qmgr_job_create(message, transport);
+       qmgr_job_link(job);
     }
 
     /*
      * Reset the candidate cache because of the new expected recipients.
-     */    
+     */
     RESET_CANDIDATE_CACHE(transport);
 
-    return(job);
+    return (job);
 }
 
 /* qmgr_job_move_limits - move unused recipient slots to the next job */
 
-void qmgr_job_move_limits(QMGR_JOB *job)
+void    qmgr_job_move_limits(QMGR_JOB * job)
 {
     QMGR_TRANSPORT *transport = job->transport;
     QMGR_MESSAGE *message = job->message;
     QMGR_JOB *next = transport->job_next_unread;
-    int rcpt_unused, msg_rcpt_unused;
+    int     rcpt_unused,
+            msg_rcpt_unused;
 
     /*
      * Find next unread job on the job list if necessary. Cache it for later.
      * This makes the amortized efficiency of this routine O(1) per job.
      */
     if (job == next) {
-        for (next = next->transport_peers.next; next; next = next->transport_peers.next)
-            if (next->message->rcpt_offset != 0)
-                break;
-        transport->job_next_unread = next;
+       for (next = next->transport_peers.next; next; next = next->transport_peers.next)
+           if (next->message->rcpt_offset != 0)
+               break;
+       transport->job_next_unread = next;
     }
 
     /*
@@ -263,54 +268,55 @@ void qmgr_job_move_limits(QMGR_JOB *job)
      */
     rcpt_unused = job->rcpt_limit - job->rcpt_count;
     msg_rcpt_unused = message->rcpt_limit - message->rcpt_count;
-    if( msg_rcpt_unused < rcpt_unused )
-        rcpt_unused = msg_rcpt_unused;
+    if (msg_rcpt_unused < rcpt_unused)
+       rcpt_unused = msg_rcpt_unused;
 
     /*
-     * Transfer the unused recipient slots back to the transport pool and
-     * to the next not-fully-read job. Job's message limits are adjusted accordingly.
+     * Transfer the unused recipient slots back to the transport pool and to
+     * the next not-fully-read job. Job's message limits are adjusted
+     * accordingly.
      */
     if (rcpt_unused > 0) {
-        job->rcpt_limit -= rcpt_unused;
-        message->rcpt_limit -= rcpt_unused;
-        transport->rcpt_unused += rcpt_unused;
-        if (next != 0 && (rcpt_unused = transport->rcpt_unused) > 0) {
-            next->rcpt_limit += rcpt_unused;
-            next->message->rcpt_limit += rcpt_unused;
-            transport->rcpt_unused = 0;
-        }
+       job->rcpt_limit -= rcpt_unused;
+       message->rcpt_limit -= rcpt_unused;
+       transport->rcpt_unused += rcpt_unused;
+       if (next != 0 && (rcpt_unused = transport->rcpt_unused) > 0) {
+           next->rcpt_limit += rcpt_unused;
+           next->message->rcpt_limit += rcpt_unused;
+           transport->rcpt_unused = 0;
+       }
     }
 }
 
 /* qmgr_job_retire - remove the job from the job list while waiting for recipients to deliver */
 
-static void qmgr_job_retire(QMGR_JOB *job)
+static void qmgr_job_retire(QMGR_JOB * job)
 {
-    char *myname = "qmgr_job_retire";
+    char   *myname = "qmgr_job_retire";
     QMGR_TRANSPORT *transport = job->transport;
 
     if (msg_verbose)
-        msg_info("%s: %s", myname, job->message->queue_id);
+       msg_info("%s: %s", myname, job->message->queue_id);
 
     /*
      * Sanity checks.
      */
     if (job->stack_level != 0)
-        msg_panic("%s: non-zero stack level (%d)", myname, job->stack_level);
+       msg_panic("%s: non-zero stack level (%d)", myname, job->stack_level);
 
     /*
-     * Make sure this job is not cached as the next unread job for this transport.
-     * The qmgr_entry_done() will make sure that the slots donated by this job
-     * are moved back to the transport pool as soon as possible.
+     * Make sure this job is not cached as the next unread job for this
+     * transport. The qmgr_entry_done() will make sure that the slots donated
+     * by this job are moved back to the transport pool as soon as possible.
      */
     qmgr_job_move_limits(job);
-    
+
     /*
      * Invalidate the candidate selection cache if necessary.
      */
     if (job == transport->candidate_cache
-        || (transport->job_stack.next == 0 && job == transport->job_list.next))
-        RESET_CANDIDATE_CACHE(transport);
+     || (transport->job_stack.next == 0 && job == transport->job_list.next))
+       RESET_CANDIDATE_CACHE(transport);
 
     /*
      * Remove the job from the job list and mark it as retired.
@@ -321,144 +327,153 @@ static void qmgr_job_retire(QMGR_JOB *job)
 
 /* qmgr_job_free - release the job structure */
 
-void qmgr_job_free(QMGR_JOB *job)
+void    qmgr_job_free(QMGR_JOB * job)
 {
-    char *myname = "qmgr_job_free";
+    char   *myname = "qmgr_job_free";
     QMGR_MESSAGE *message = job->message;
     QMGR_TRANSPORT *transport = job->transport;
 
     if (msg_verbose)
-        msg_info("%s: %s %s", myname, message->queue_id, transport->name);
+       msg_info("%s: %s %s", myname, message->queue_id, transport->name);
 
     /*
      * Sanity checks.
      */
     if (job->rcpt_count)
-        msg_panic("%s: non-zero recipient count (%d)", myname, job->rcpt_count);
+       msg_panic("%s: non-zero recipient count (%d)", myname, job->rcpt_count);
 
     /*
      * Remove the job from the job stack if necessary.
      */
     if (job->stack_level > 0)
-        qmgr_job_pop(job);
+       qmgr_job_pop(job);
 
     /*
      * Return any remaining recipient slots back to the recipient slots pool.
      */
     qmgr_job_move_limits(job);
     if (job->rcpt_limit)
-        msg_panic("%s: recipient slots leak (%d)", myname, job->rcpt_limit);
-    
+       msg_panic("%s: recipient slots leak (%d)", myname, job->rcpt_limit);
+
     /*
      * Invalidate the candidate selection cache if necessary.
      */
     if (job == transport->candidate_cache
-        || (transport->job_stack.next == 0 && job == transport->job_list.next))
-        RESET_CANDIDATE_CACHE(transport);
+     || (transport->job_stack.next == 0 && job == transport->job_list.next))
+       RESET_CANDIDATE_CACHE(transport);
 
     /*
-     * Unlink and discard the structure. Check if the job is still on the transport
-     * job list or if it was already retired before unlinking it.
+     * Unlink and discard the structure. Check if the job is still on the
+     * transport job list or if it was already retired before unlinking it.
      */
     if (job->stack_level >= 0)
-        QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers);
+       QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers);
     QMGR_LIST_UNLINK(message->job_list, QMGR_JOB *, job, message_peers);
-    htable_delete(transport->job_byname, message->queue_id, (void (*) (char *)) 0) ;
+    htable_delete(transport->job_byname, message->queue_id, (void (*) (char *)) 0);
     htable_free(job->peer_byname, (void (*) (char *)) 0);
     myfree((char *) job);
 }
 
-/* qmgr_job_count_slots - maintain the delivery slots' counters */
+/* qmgr_job_count_slots - maintain the delivery slot counters */
 
-static void qmgr_job_count_slots(QMGR_JOB *current, QMGR_JOB *job)
+static void qmgr_job_count_slots(QMGR_JOB * current, QMGR_JOB * job)
 {
+
     /*
-     * Count the number of delivery slots used during the delivery
-     * of the selected job and also the number of delivery slots
-     * available for preemption.
-     *
+     * Count the number of delivery slots used during the delivery of the
+     * selected job. Also count the number of delivery slots available for
+     * preemption.
+     * 
      * However, suppress any slot counting if we didn't start regular delivery
      * of the selected job yet.
      */
     if (job == current || job->slots_used > 0) {
-        job->slots_used++;
-        job->slots_available++;
+       job->slots_used++;
+       job->slots_available++;
     }
-    
+
     /*
      * If the selected job is not the current job, its chance to be chosen by
      * qmgr_job_candidate() has slightly changed. If we would like to make
-     * the candidate cache completely transparent, we should invalidate it now.
-     *
+     * the candidate cache completely transparent, we should invalidate it
+     * now.
+     * 
      * However, this case should usually happen only at "end of current job"
      * phase, when it's unlikely that the current job can be preempted
      * anyway.  And because it's likely to happen quite often then, we
-     * intentionally don't reset the cache, to safe some cycles. 
-     * Furthermore, the cache times out every second anyway.
+     * intentionally don't reset the cache, to safe some cycles. Furthermore,
+     * the cache times out every second anyway.
      */
 #if 0
     if (job != current)
-        RESET_CANDIDATE_CACHE(job->transport);
+       RESET_CANDIDATE_CACHE(job->transport);
 #endif
 }
 
 /* qmgr_job_candidate - find best job candidate for preempting given job */
 
-static QMGR_JOB *qmgr_job_candidate(QMGR_JOB *current)
+static QMGR_JOB *qmgr_job_candidate(QMGR_JOB * current)
 {
     QMGR_TRANSPORT *transport = current->transport;
-    QMGR_JOB *job, *best_job = 0;
-    float score, best_score = 0.0;
-    int max_slots, max_needed_entries, max_total_entries;
-    int delay;
-    time_t now = event_time();
-    
+    QMGR_JOB *job,
+           *best_job = 0;
+    float   score,
+            best_score = 0.0;
+    int     max_slots,
+            max_needed_entries,
+            max_total_entries;
+    int     delay;
+    time_t  now = event_time();
+
     /*
      * Fetch the result directly from the cache if the cache is still valid.
-     *
-     * Note that we cache negative results too, so the cache must be
-     * invalidated by resetting the cache time, not the candidate pointer itself.
+     * 
+     * Note that we cache negative results too, so the cache must be invalidated
+     * by resetting the cache time, not the candidate pointer itself.
      */
     if (transport->candidate_cache_time == now)
-        return (transport->candidate_cache);
-    
+       return (transport->candidate_cache);
+
     /*
-     * Estimate the minimum amount of delivery slots that can ever be accumulated
-     * for the given job. All jobs that won't fit into these slots are excluded
-     * from the candidate selection.
+     * Estimate the minimum amount of delivery slots that can ever be
+     * accumulated for the given job. All jobs that won't fit into these
+     * slots are excluded from the candidate selection.
      */
     max_slots = (MIN_ENTRIES(current) - current->selected_entries
-                + current->slots_available) / transport->slot_cost;
+                + current->slots_available) / transport->slot_cost;
 
     /*
-     * Select the candidate with best time_since_queued/total_recipients score.
-     * In addition to jobs which don't meet the max_slots limit, skip also jobs
-     * which don't have any selectable entries at the moment.
-     *
-     * By the way, the selection is reasonably resistant to OS time warping, too.
-     *
-     * However, don't bother searching if we can't find anything suitable anyway.
+     * Select the candidate with best time_since_queued/total_recipients
+     * score. In addition to jobs which don't meet the max_slots limit, skip
+     * also jobs which don't have any selectable entries at the moment.
+     * 
+     * By the way, the selection is reasonably resistant to OS time warping,
+     * too.
+     * 
+     * However, don't bother searching if we can't find anything suitable
+     * anyway.
      */
     if (max_slots > 0) {
-        for (job = transport->job_list.next; job; job = job->transport_peers.next) {
-            if (job->stack_level != 0 || job == current)
-                continue;
-            max_total_entries = MAX_ENTRIES(job);
-            max_needed_entries = max_total_entries - job->selected_entries;
-            delay = now - job->message->queued_time + 1;
-            if (max_needed_entries > 0 && max_needed_entries <= max_slots) {
-                score = (float) delay / max_total_entries;
-                if (score > best_score) {
-                    best_score = score;
-                    best_job = job;
-                }
-            }
-            /*
-             * Stop early if the best score is as good as it can get.
-             */
-            if (delay <= best_score)
-                break;
-        }
+       for (job = transport->job_list.next; job; job = job->transport_peers.next) {
+           if (job->stack_level != 0 || job == current)
+               continue;
+           max_total_entries = MAX_ENTRIES(job);
+           max_needed_entries = max_total_entries - job->selected_entries;
+           delay = now - job->message->queued_time + 1;
+           if (max_needed_entries > 0 && max_needed_entries <= max_slots) {
+               score = (float) delay / max_total_entries;
+               if (score > best_score) {
+                   best_score = score;
+                   best_job = job;
+               }
+           }
+
+           /*
+            * Stop early if the best score is as good as it can get.
+            */
+           if (delay <= best_score)
+               break;
+       }
     }
 
     /*
@@ -472,33 +487,34 @@ static QMGR_JOB *qmgr_job_candidate(QMGR_JOB *current)
 
 /* qmgr_job_preempt - preempt large message with smaller one */
 
-static QMGR_JOB * qmgr_job_preempt(QMGR_JOB *current)
+static QMGR_JOB *qmgr_job_preempt(QMGR_JOB * current)
 {
-    char *myname = "qmgr_job_preempt";
+    char   *myname = "qmgr_job_preempt";
     QMGR_TRANSPORT *transport = current->transport;
     QMGR_JOB *job;
-    int rcpt_slots;
-    
+    int     rcpt_slots;
+
     /*
-     * Suppress preempting completely if the current job is not big enough
-     * to accumulate even the mimimal number of slots required.
-     *
-     * Also, don't look for better job candidate if there are no available
-     * slots yet (the count can get negative due to the slot loans below).
+     * Suppress preempting completely if the current job is not big enough to
+     * accumulate even the mimimal number of slots required.
+     * 
+     * Also, don't look for better job candidate if there are no available slots
+     * yet (the count can get negative due to the slot loans below).
      */
     if (current->slots_available <= 0
-        || MAX_ENTRIES(current) < transport->min_slots * transport->slot_cost)
-        return (current);
+      || MAX_ENTRIES(current) < transport->min_slots * transport->slot_cost)
+       return (current);
 
     /*
      * Find best candidate for preempting the current job.
-     *
-     * Note that the function also takes care that the candidate fits within
-     * the number of delivery slots the current job can ever accumulate yet.
-     */    
+     * 
+     * Note that the function also takes care that the candidate fits within the
+     * number of delivery slots which the current job is still able to
+     * accumulate.
+     */
     if ((job = qmgr_job_candidate(current)) == 0)
-        return (current);
-    
+       return (current);
+
     /*
      * Sanity checks.
      */
@@ -508,89 +524,90 @@ static QMGR_JOB * qmgr_job_preempt(QMGR_JOB *current)
        msg_panic("%s: already on the job stack (%d)", myname, job->stack_level);
 
     /*
-     * Check if there is enough available delivery slots accumulated
-     * to preempt the current job.
-     *
-     * The slot loaning scheme improves the average message response time. 
-     * Note that the loan only allows the preemption happen earlier, though.
-     * It doesn't affect how many slots have to be "paid" - the full number
-     * of slots required will have to accumulate later before next
-     * preemption on the same stack level can happen anyway.
+     * Check if there is enough available delivery slots accumulated to
+     * preempt the current job.
+     * 
+     * The slot loaning scheme improves the average message response time. Note
+     * that the loan only allows the preemption happen earlier, though. It
+     * doesn't affect how many slots have to be "paid" - the full number of
+     * slots required has to be accumulated later before next preemption on
+     * the same stack level can happen in either case.
      */
-    if (current->slots_available / transport->slot_cost 
-        + transport->slot_loan
-        < (MAX_ENTRIES(job) - job->selected_entries)
-        * transport->slot_loan_factor / 100.0)
-        return (current);
+    if (current->slots_available / transport->slot_cost
+       + transport->slot_loan
+       < (MAX_ENTRIES(job) - job->selected_entries)
+       * transport->slot_loan_factor / 100.0)
+       return (current);
 
     /*
      * Preempt the current job.
      */
     QMGR_LIST_PREPEND(transport->job_stack, job, stack_peers);
     job->stack_level = current->stack_level + 1;
-    
+
     /*
-     * Add part of extra recipient slots reserved for preempting jobs
-     * to the new current job if necessary.
-     *
-     * Note that transport->rcpt_unused is within <-rcpt_per_stack,0> in such case.
+     * Add part of extra recipient slots reserved for preempting jobs to the
+     * new current job if necessary.
+     * 
+     * Note that transport->rcpt_unused is within <-rcpt_per_stack,0> in such
+     * case.
      */
     if (job->message->rcpt_offset != 0) {
-        rcpt_slots = (transport->rcpt_per_stack + transport->rcpt_unused + 1) / 2;
-        job->rcpt_limit += rcpt_slots;
-        job->message->rcpt_limit += rcpt_slots;
-        transport->rcpt_unused -= rcpt_slots;
+       rcpt_slots = (transport->rcpt_per_stack + transport->rcpt_unused + 1) / 2;
+       job->rcpt_limit += rcpt_slots;
+       job->message->rcpt_limit += rcpt_slots;
+       transport->rcpt_unused -= rcpt_slots;
     }
 
     /*
-     * Candidate cache must be reset because the current job has changed completely.
+     * Candidate cache must be reset because the current job has changed
+     * completely.
      */
     RESET_CANDIDATE_CACHE(transport);
 
     if (msg_verbose)
-        msg_info("%s: %s by %s", myname, current->message->queue_id,
-                                       job->message->queue_id);
+       msg_info("%s: %s by %s", myname, current->message->queue_id,
+                job->message->queue_id);
 
     return (job);
 }
 
 /* qmgr_job_pop - remove the job from the job preemption stack */
 
-static void qmgr_job_pop(QMGR_JOB *job)
+static void qmgr_job_pop(QMGR_JOB * job)
 {
     QMGR_TRANSPORT *transport = job->transport;
     QMGR_JOB *parent;
-    
+
     if (msg_verbose)
-        msg_info("qmgr_job_pop: %s", job->message->queue_id);
+       msg_info("qmgr_job_pop: %s", job->message->queue_id);
 
     /*
-     * Adjust the number of delivery slots available to preempt
-     * job's parent.
+     * Adjust the number of delivery slots available to preempt job's parent.
+     * 
+     * Note that we intentionally do not adjust slots_used of the parent. Doing
+     * so would decrease the maximum per message inflation factor if the
+     * preemption appeared near the end of parent delivery.
+     * 
+     * For the same reason we do not adjust parent's slots_available if the
+     * parent is not the original parent preempted by the selected job (i.e.,
+     * the original parent job has already completed).
      * 
-     * Note that we intentionally do not adjust slots_used of the parent.
-     * Doing so would decrease the maximum per message inflation factor
-     * if the preemption appeared near the end of parent delivery.
-     *
-     * For the same reason we do not adjust parent's slots_available
-     * if the parent is not the original parent preempted by the
-     * selected job (i.e., the original parent job has already completed).
-     *
-     * The special case when the head of the job list was preempted and
-     * then delivered before the preempting job itself is taken care of too.
+     * The special case when the head of the job list was preempted and then
+     * delivered before the preempting job itself is taken care of too.
      * Otherwise we would decrease available slot counter of some job that
      * was not in fact preempted yet.
      */
     if (((parent = job->stack_peers.next) != 0
-        || ((parent = transport->job_list.next) != 0 && parent->slots_used > 0))
-        && job->stack_level == parent->stack_level + 1)
-        parent->slots_available -= job->slots_used * transport->slot_cost;
+    || ((parent = transport->job_list.next) != 0 && parent->slots_used > 0))
+       && job->stack_level == parent->stack_level + 1)
+       parent->slots_available -= job->slots_used * transport->slot_cost;
 
     /*
      * Invalidate the candidate selection cache if necessary.
      */
     if (job == transport->job_stack.next)
-        RESET_CANDIDATE_CACHE(transport);
+       RESET_CANDIDATE_CACHE(transport);
 
     /*
      * Remove the job from the job stack and reinitialize the slot counters.
@@ -603,13 +620,13 @@ static void qmgr_job_pop(QMGR_JOB *job)
 
 /* qmgr_job_peer_select - select next peer suitable for delivery */
 
-static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB *job)
+static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB * job)
 {
     QMGR_PEER *peer;
     QMGR_MESSAGE *message = job->message;
-    
+
     if (HAS_ENTRIES(job) && (peer = qmgr_peer_select(job)) != 0)
-        return (peer);
+       return (peer);
 
     /*
      * Try reading in more recipients. Note that we do not try to read them
@@ -617,9 +634,9 @@ static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB *job)
      * recipient grouping. We waited until reading more is really necessary.
      */
     if (message->rcpt_offset != 0 && message->rcpt_limit > message->rcpt_count) {
-        qmgr_message_realloc(message);
-        if (HAS_ENTRIES(job))
-            return (qmgr_peer_select(job));
+       qmgr_message_realloc(message);
+       if (HAS_ENTRIES(job))
+           return (qmgr_peer_select(job));
     }
     return (0);
 }
@@ -628,102 +645,104 @@ static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB *job)
 
 QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *transport)
 {
-    QMGR_JOB *job, *current, *next;
+    QMGR_JOB *job,
+           *current,
+           *next;
     QMGR_PEER *peer;
     QMGR_ENTRY *entry;
-    
+
     /*
      * Select the "current" job.
      */
     if ((current = transport->job_stack.next) == 0
-        && (current = transport->job_list.next) == 0)
-        return (0);
-    
+       && (current = transport->job_list.next) == 0)
+       return (0);
+
     /*
      * Exercise the preempting algorithm if enabled.
-     *
+     * 
      * The slot_cost equal to 1 causes the algorithm to degenerate and is
      * therefore disabled too.
      */
     if (transport->slot_cost >= 2)
-        current = qmgr_job_preempt(current);
+       current = qmgr_job_preempt(current);
 
     /*
      * Select next entry suitable for delivery. First check the stack of
      * preempting jobs, then the list of all remaining jobs in FIFO order.
-     *
-     * Note that although the loops may look inefficient, they only serve as
-     * recovery mechanism when an entry of the current job itself can't be
+     * 
+     * Note that although the loops may look inefficient, they only serve as a
+     * recovery mechanism when an entry of the current job itself can't be
      * selected due peer concurrency restrictions. In most cases some entry
      * of the current job itself is selected.
-     *
+     * 
      * Note that both loops also take care of getting the "stall" current job
      * (job with no entries currently available) out of the way if necessary.
-     * Stall jobs can appear in case of multi-transport messages whose recipients
-     * don't fit in-core at once. Some jobs created by such message may have
-     * only few recipients and would block the job queue until all other
-     * jobs of the message are delivered. Trying to read in more recipients
-     * of such jobs each selection would also break the per peer recipient
-     * grouping of the other jobs. That's why we retire such jobs below.
+     * Stall jobs can appear in case of multi-transport messages whose
+     * recipients don't fit in-core at once. Some jobs created by such
+     * message may have only few recipients and would block the job queue
+     * until all other jobs of the message are delivered. Trying to read in
+     * more recipients of such jobs each selection would also break the per
+     * peer recipient grouping of the other jobs. That's why we retire such
+     * jobs below.
      */
     for (job = transport->job_stack.next; job; job = next) {
-        next = job->stack_peers.next;
-        if ((peer = qmgr_job_peer_select(job)) != 0) {
-            entry = qmgr_entry_select(peer);
-            qmgr_job_count_slots(current, job);
-
-            /*
-             * In case we selected the very last job entry, remove the job
-             * from the job stack and the job list right now.
-             *
-             * This action uses the assumption that once the job entry
-             * has been selected, it can be unselected only before the
-             * message ifself is deferred. Thus the job with all entries
-             * selected can't re-appear with more entries available for
-             * selection again (without reading in more entries from
-             * the queue file, which in turn invokes qmgr_job_obtain()
-             * which re-links the job back on the list if necessary).
-             *
-             * Note that qmgr_job_move_limits() transfers the recipients slots
-             * correctly even if the job is unlinked from the job list
-             * thanks to the job_next_unread caching.
-             */
-            if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0) {
-                qmgr_job_pop(job);
-                qmgr_job_retire(job);
-            }
-            return (entry);
-        }
-        else if (job == current && !HAS_ENTRIES(job)) {
-            qmgr_job_pop(job);
-            qmgr_job_retire(job);
-            current = next ? next : transport->job_list.next;
-        }
+       next = job->stack_peers.next;
+       if ((peer = qmgr_job_peer_select(job)) != 0) {
+           entry = qmgr_entry_select(peer);
+           qmgr_job_count_slots(current, job);
+
+           /*
+            * In case we selected the very last job entry, remove the job
+            * from the job stack and the job list right now.
+            * 
+            * This action uses the assumption that once the job entry has been
+            * selected, it can be unselected only before the message ifself
+            * is deferred. Thus the job with all entries selected can't
+            * re-appear with more entries available for selection again
+            * (without reading in more entries from the queue file, which in
+            * turn invokes qmgr_job_obtain() which re-links the job back on
+            * the list if necessary).
+            * 
+            * Note that qmgr_job_move_limits() transfers the recipients slots
+            * correctly even if the job is unlinked from the job list thanks
+            * to the job_next_unread caching.
+            */
+           if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0) {
+               qmgr_job_pop(job);
+               qmgr_job_retire(job);
+           }
+           return (entry);
+       } else if (job == current && !HAS_ENTRIES(job)) {
+           qmgr_job_pop(job);
+           qmgr_job_retire(job);
+           current = next ? next : transport->job_list.next;
+       }
     }
-    
+
     /*
-     * Try the regular job list if there is nothing (suitable) on the job stack.
+     * Try the regular job list if there is nothing (suitable) on the job
+     * stack.
      */
     for (job = transport->job_list.next; job; job = next) {
-        next = job->transport_peers.next;
-        if (job->stack_level != 0)
-            continue;
-        if ((peer = qmgr_job_peer_select(job)) != 0) {
-            entry = qmgr_entry_select(peer);
-            qmgr_job_count_slots(current, job);
-
-            /*
-             * In case we selected the very last job entry, remove the job
-             * from the job list right away.
-             */
-            if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0)
-                qmgr_job_retire(job);
-            return (entry);
-        }
-        else if (job == current && !HAS_ENTRIES(job)) {
-            qmgr_job_retire(job);
-            current = next;
-        }
+       next = job->transport_peers.next;
+       if (job->stack_level != 0)
+           continue;
+       if ((peer = qmgr_job_peer_select(job)) != 0) {
+           entry = qmgr_entry_select(peer);
+           qmgr_job_count_slots(current, job);
+
+           /*
+            * In case we selected the very last job entry, remove the job
+            * from the job list right away.
+            */
+           if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0)
+               qmgr_job_retire(job);
+           return (entry);
+       } else if (job == current && !HAS_ENTRIES(job)) {
+           qmgr_job_retire(job);
+           current = next;
+       }
     }
     return (0);
 }
index f40f75c50e05689ed3e4af2db9d4807600929d49..7814ff632d207fb199323c37c86bc010984325d1 100644 (file)
@@ -51,7 +51,7 @@
 /*     structure members. A null result means that the file could not be
 /*     read or that the file contained incorrect information. Recipient
 /*     limit imposed this time is based on the position of the message
-/*     job(s) on corresponding job list(s).
+/*     job(s) on corresponding transport job list(s).
 /*
 /*     qmgr_message_free() destroys an in-core message structure and makes
 /*     the resources available for reuse. It is an error to destroy
@@ -83,7 +83,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
-#include <stdio.h>      /* sscanf() */
+#include <stdio.h>                     /* sscanf() */
 
 #ifdef STRCASECMP_IN_STRINGS_H
 #include <strings.h>
@@ -197,34 +197,36 @@ static int qmgr_message_open(QMGR_MESSAGE *message)
     return (0);
 }
 
-/* qmgr_message_oldstyle_scan - extract required information from old style queue file */
+/* qmgr_message_oldstyle_scan - extract required information from an old style queue file */
 
 static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
 {
     VSTRING *buf;
-    long    orig_offset, curr_offset, extra_offset;
+    long    orig_offset,
+            curr_offset,
+            extra_offset;
     int     rec_type;
-    char    *start;
+    char   *start;
 
     /*
      * Initialize. No early returns or we have a memory leak.
      */
     buf = vstring_alloc(100);
     if ((orig_offset = vstream_ftell(message->fp)) < 0)
-        msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
+       msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
 
     /*
-     * Rewind to the very begining to make sure we see all records.
+     * Rewind to the very beginning to make sure we see all records.
      */
     if (vstream_fseek(message->fp, 0, SEEK_SET) < 0)
-        msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
+       msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
 
     /*
-     * Scan through the old style queue file. Count the total number
-     * of recipients and find the data/extra sections offsets.
-     * Note that the new queue files require that data_size equals
-     * extra_offset - data_offset, so we set data_size to this as well
-     * and ignore the size record itself completely.
+     * Scan through the old style queue file. Count the total number of
+     * recipients and find the data/extra sections offsets. Note that the new
+     * queue files require that data_size equals extra_offset - data_offset,
+     * so we set data_size to this as well and ignore the size record itself
+     * completely.
      */
     message->rcpt_unread = 0;
     do {
@@ -239,18 +241,18 @@ static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
                msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
            if ((extra_offset = atol(start)) <= curr_offset)
                msg_fatal("bad extra offset %s file %s",
-                        start, VSTREAM_PATH(message->fp));
+                         start, VSTREAM_PATH(message->fp));
            if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
                msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-            message->data_size = extra_offset - message->data_offset;
+           message->data_size = extra_offset - message->data_offset;
        }
     } while (rec_type > 0 && rec_type != REC_TYPE_END);
-    
+
     /*
      * Clean up.
      */
     if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0)
-        msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
+       msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
     vstring_free(buf);
 
     /*
@@ -281,15 +283,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
     /*
      * If we re-open this file, skip over on-file recipient records that we
      * already looked at, and reset the in-core recipient address list.
-     *
-     * For the first time, the message recipient limit is calculated from
-     * the global recipient limit. This is to avoid reading little recipients
+     * 
+     * For the first time, the message recipient limit is calculated from the
+     * global recipient limit. This is to avoid reading little recipients
      * when the active queue is near empty. When the queue becomes full, only
      * the necessary amount is read in core. Such priming is necessary
      * because there are no message jobs yet.
-     *
+     * 
      * For the next time, the recipient limit is based solely on the message
-     * jobs' positions in the job queues and/or job stacks.
+     * jobs' positions in the job lists and/or job stacks.
      */
     if (message->rcpt_offset) {
        if (message->rcpt_list.len)
@@ -298,11 +300,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
            msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
        message->rcpt_offset = 0;
        recipient_limit = message->rcpt_limit - message->rcpt_count;
-    }
-    else {
-        recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count;
-        if (recipient_limit < message->rcpt_limit)
-            recipient_limit = message->rcpt_limit;
+    } else {
+       recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count;
+       if (recipient_limit < message->rcpt_limit)
+           recipient_limit = message->rcpt_limit;
     }
 
     /*
@@ -312,49 +313,50 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      * may appear before or after the message content, so we keep reading
      * from the queue file until we have enough recipients (rcpt_offset != 0)
      * and until we know where the message content starts (data_offset != 0).
-     *
+     * 
      * Note that the total recipient count record is accurate only for fresh
-     * queue files. After some of the recipients are marked as done and
-     * the queue file is deferred, it can be used as upper bound estimate
-     * only. Fortunately, this poses no major problem on the scheduling
-     * algorithm, as the only impact is that the already deferred messages
-     * are not chosen by qmgr_job_candidate() as often as they could.
+     * queue files. After some of the recipients are marked as done and the
+     * queue file is deferred, it can be used as upper bound estimate only.
+     * Fortunately, this poses no major problem on the scheduling algorithm,
+     * as the only impact is that the already deferred messages are not
+     * chosen by qmgr_job_candidate() as often as they could.
      */
     do {
        if ((curr_offset = vstream_ftell(message->fp)) < 0)
            msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
-        if (curr_offset == message->data_offset && curr_offset > 0) {
-            extra_offset = curr_offset + message->data_size;
-            if (extra_offset <= curr_offset)
+       if (curr_offset == message->data_offset && curr_offset > 0) {
+           extra_offset = curr_offset + message->data_size;
+           if (extra_offset <= curr_offset)
                msg_fatal("bad extra offset %ld file %s",
-                        extra_offset, VSTREAM_PATH(message->fp));
-            if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
-                msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-            curr_offset = extra_offset;
-        }
+                         extra_offset, VSTREAM_PATH(message->fp));
+           if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
+               msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
+           curr_offset = extra_offset;
+       }
        rec_type = rec_get(message->fp, buf, 0);
        start = vstring_str(buf);
        if (rec_type == REC_TYPE_SIZE) {
            if (message->data_size == 0) {
-               switch (sscanf(start, "%ld %ld %d", &message->data_size,
-                               &message->data_offset, &message->rcpt_unread))
-               {
-                case 1:
-                    /*
-                     * Gather data_size, data_offset and rcpt_unread values
-                     * from the old style queue file.
-                     */
-                    qmgr_message_oldstyle_scan(message);
-                    break;
-                case 3:
-                    /*
-                     * No extra work for new style queue files.
-                     */
-                    break;
-                default:
-                    msg_fatal("%s: weird size record", message->queue_id);
-                    break;
-               }
+               switch (sscanf(start, "%ld %ld %d", &message->data_size,
+                           &message->data_offset, &message->rcpt_unread)) {
+               case 1:
+
+                   /*
+                    * Gather data_size, data_offset and rcpt_unread values
+                    * from the old style queue file.
+                    */
+                   qmgr_message_oldstyle_scan(message);
+                   break;
+               case 3:
+
+                   /*
+                    * No extra work for new style queue files.
+                    */
+                   break;
+               default:
+                   msg_fatal("%s: weird size record", message->queue_id);
+                   break;
+               }
            }
        } else if (rec_type == REC_TYPE_TIME) {
            if (message->arrival_time == 0)
@@ -366,12 +368,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
            if (message->sender == 0) {
                message->sender = mystrdup(start);
                opened(message->queue_id, message->sender,
-                      message->data_size, "queue %s", message->queue_name);
+                      message->data_size, message->rcpt_unread,
+                      "queue %s", message->queue_name);
            }
        } else if (rec_type == REC_TYPE_DONE) {
            if (curr_offset > message->unread_offset) {
-               message->unread_offset = curr_offset;
-               message->rcpt_unread--;
+               message->unread_offset = curr_offset;
+               message->rcpt_unread--;
            }
        } else if (rec_type == REC_TYPE_RCPT) {
            if (message->rcpt_list.len < recipient_limit) {
@@ -432,9 +435,9 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
      */
     if (message->rcpt_unread < 0
        || (message->rcpt_offset == 0 && message->rcpt_unread != 0)) {
-       msg_warn("%s: rcpt count mismatch (%d)",
-                       message->queue_id, message->rcpt_unread);
-       message->rcpt_unread = 0;
+       msg_warn("%s: rcpt count mismatch (%d)",
+                message->queue_id, message->rcpt_unread);
+       message->rcpt_unread = 0;
     }
     if (message->arrival_time == 0
        || message->sender == 0
@@ -777,13 +780,12 @@ static void qmgr_message_assign(QMGR_MESSAGE *message)
                || !LIMIT_OK(queue->transport->recipient_limit,
                             entry->rcpt_list.len)) {
                if (job == 0 || queue->transport != job->transport) {
-                   /* FIXME: randomly rotate the peer list of previous job */
                    job = qmgr_job_obtain(message, queue->transport);
                    peer = 0;
                }
                if (peer == 0 || queue != peer->queue) {
                    if ((peer = qmgr_peer_find(job, queue)) == 0)
-                       peer = qmgr_peer_create(job, queue);
+                       peer = qmgr_peer_create(job, queue);
                }
                entry = qmgr_entry_create(peer, message);
                job->read_entries++;
@@ -803,9 +805,9 @@ static void qmgr_message_assign(QMGR_MESSAGE *message)
 static void qmgr_message_move_limits(QMGR_MESSAGE *message)
 {
     QMGR_JOB *job;
-    
+
     for (job = message->job_list.next; job; job = job->message_peers.next)
-        qmgr_job_move_limits(job);
+       qmgr_job_move_limits(job);
 }
 
 /* qmgr_message_free - release memory for in-core message structure */
@@ -813,12 +815,13 @@ static void qmgr_message_move_limits(QMGR_MESSAGE *message)
 void    qmgr_message_free(QMGR_MESSAGE *message)
 {
     QMGR_JOB *job;
+
     if (message->refcount != 0)
        msg_panic("qmgr_message_free: reference len: %d", message->refcount);
     if (message->fp)
        msg_panic("qmgr_message_free: queue file is open");
     while ((job = message->job_list.next) != 0)
-        qmgr_job_free(job);
+       qmgr_job_free(job);
     myfree(message->queue_id);
     myfree(message->queue_name);
     if (message->sender)
@@ -887,8 +890,8 @@ QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
        qmgr_message_sort(message);
        qmgr_message_assign(message);
        qmgr_message_close(message);
-       if(message->rcpt_offset == 0)
-            qmgr_message_move_limits(message);
+       if (message->rcpt_offset == 0)
+           qmgr_message_move_limits(message);
        return (message);
     }
 }
@@ -923,8 +926,8 @@ QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message)
        qmgr_message_sort(message);
        qmgr_message_assign(message);
        qmgr_message_close(message);
-       if(message->rcpt_offset == 0)
-            qmgr_message_move_limits(message);
+       if (message->rcpt_offset == 0)
+           qmgr_message_move_limits(message);
        return (message);
     }
 }
index 72953d3a45b15efcbe44a2ca5ea0c81f2a37637e..b445a6793df564772c9aacfb0bc464b86a8b01bc 100644 (file)
 /*
 /*     qmgr_peer_create() creates an empty peer structure for the named
 /*     job and destination. It is an error to call this function
-/*     if an peer for given combination already exists.
+/*     if a peer for given combination already exists.
 /*
 /*     qmgr_peer_find() looks up the peer for the named destination
-/*     for the named job. A null result means that the queue
+/*     for the named job. A null result means that the peer
 /*     was not found.
 /*
-/*     qmgr_peer_free() disposes of a per-job queue after all
+/*     qmgr_peer_free() disposes of a per-job peer after all
 /*     its entries have been taken care of. It is an error to dispose
 /*     of a peer still in use.
 /*
@@ -42,7 +42,7 @@
 /*     has messages pending delivery.  This routine implements
 /*     round-robin search among job's peers.
 /* DIAGNOSTICS
-/*     Panic: consistency check failure.
+/*     None
 /* LICENSE
 /* .ad
 /* .fi
@@ -68,7 +68,7 @@
 
 /* qmgr_peer_create - create and initialize message peer structure */
 
-QMGR_PEER *qmgr_peer_create(QMGR_JOB *job, QMGR_QUEUE *queue)
+QMGR_PEER *qmgr_peer_create(QMGR_JOB * job, QMGR_QUEUE *queue)
 {
     QMGR_PEER *peer;
 
@@ -84,41 +84,41 @@ QMGR_PEER *qmgr_peer_create(QMGR_JOB *job, QMGR_QUEUE *queue)
 
 /* qmgr_peer_free - release peer structure */
 
-void qmgr_peer_free(QMGR_PEER *peer)
+void    qmgr_peer_free(QMGR_PEER * peer)
 {
     QMGR_JOB *job = peer->job;
 
     QMGR_LIST_UNLINK(job->peer_list, QMGR_PEER *, peer, peers);
-    htable_delete(job->peer_byname, peer->queue->name, (void (*) (char *)) 0) ;
+    htable_delete(job->peer_byname, peer->queue->name, (void (*) (char *)) 0);
     myfree((char *) peer);
 }
 
 /* qmgr_peer_find - lookup peer associated with given job and queue */
 
-QMGR_PEER *qmgr_peer_find(QMGR_JOB *job, QMGR_QUEUE *queue)
+QMGR_PEER *qmgr_peer_find(QMGR_JOB * job, QMGR_QUEUE *queue)
 {
     return ((QMGR_PEER *) htable_find(job->peer_byname, queue->name));
 }
 
 /* qmgr_peer_select - select next peer suitable for delivery within given job */
 
-QMGR_PEER *qmgr_peer_select(QMGR_JOB *job)
+QMGR_PEER *qmgr_peer_select(QMGR_JOB * job)
 {
     QMGR_PEER *peer;
     QMGR_QUEUE *queue;
-    
+
     /*
      * If we find a suitable site, rotate the list to enforce round-robin
      * selection. See similar selection code in qmgr_transport_select().
      */
     for (peer = job->peer_list.next; peer; peer = peer->peers.next) {
-        queue = peer->queue;
-        if (queue->window > queue->busy_refcount && peer->entry_list.next != 0) {
-            QMGR_LIST_ROTATE(job->peer_list, peer, peers);
-            if (msg_verbose)
-               msg_info("qmgr_peer_select: %s %s", job->message->queue_id, queue->name);
+       queue = peer->queue;
+       if (queue->window > queue->busy_refcount && peer->entry_list.next != 0) {
+           QMGR_LIST_ROTATE(job->peer_list, peer, peers);
+           if (msg_verbose)
+               msg_info("qmgr_peer_select: %s %s", job->message->queue_id, queue->name);
            return (peer);
-        }
+       }
     }
     return (0);
 }
index 9fc1aabf533e15a54558d880ac6873f18e8fefe9..e87ee7c4445c7ffa61320c36d3ba604aae87468c 100644 (file)
@@ -320,10 +320,10 @@ QMGR_TRANSPORT *qmgr_transport_create(const char *name)
      */
     transport->dest_concurrency_limit =
        get_mail_conf_int2(name, _DEST_CON_LIMIT,
-                       var_dest_con_limit, 0, 0);
+                          var_dest_con_limit, 0, 0);
     transport->recipient_limit =
        get_mail_conf_int2(name, _DEST_RCPT_LIMIT,
-                       var_dest_rcpt_limit, 0, 0);
+                          var_dest_rcpt_limit, 0, 0);
 
     if (transport->dest_concurrency_limit == 0
        || transport->dest_concurrency_limit >= var_init_dest_concurrency)
@@ -332,18 +332,18 @@ QMGR_TRANSPORT *qmgr_transport_create(const char *name)
        transport->init_dest_concurrency = transport->dest_concurrency_limit;
 
     transport->slot_cost = get_mail_conf_int2(name, _DELIVERY_SLOT_COST,
-                        var_delivery_slot_cost, 0, 0);
+                                             var_delivery_slot_cost, 0, 0);
     transport->slot_loan = get_mail_conf_int2(name, _DELIVERY_SLOT_LOAN,
-                        var_delivery_slot_loan, 0, 0);
+                                             var_delivery_slot_loan, 0, 0);
     transport->slot_loan_factor =
-        100 - get_mail_conf_int2(name, _DELIVERY_SLOT_DISCOUNT,
-                        var_delivery_slot_discount, 0, 100);
+       100 - get_mail_conf_int2(name, _DELIVERY_SLOT_DISCOUNT,
+                                var_delivery_slot_discount, 0, 100);
     transport->min_slots = get_mail_conf_int2(name, _MIN_DELIVERY_SLOTS,
-                        var_min_delivery_slots, 0, 0);
+                                             var_min_delivery_slots, 0, 0);
     transport->rcpt_unused = get_mail_conf_int2(name, _XPORT_RCPT_LIMIT,
-                        var_xport_rcpt_limit, 0, 0);
+                                               var_xport_rcpt_limit, 0, 0);
     transport->rcpt_per_stack = get_mail_conf_int2(name, _STACK_RCPT_LIMIT,
-                        var_stack_rcpt_limit, 0, 0);
+                                               var_stack_rcpt_limit, 0, 0);
 
     transport->queue_byname = htable_create(0);
     QMGR_LIST_INIT(transport->queue_list);
index dedf87c8e64b2dbbbe526acd525791692c99d382..3ff29848926de565930f15deba884a34418a25b8 100644 (file)
@@ -5,7 +5,7 @@
 /*     Postfix alias database maintenance
 /* SYNOPSIS
 /* .fi
-/*     \fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
+/*     \fBpostalias\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR]
 /*             [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
 /*             [\fIfile_type\fR:]\fIfile_name\fR ...
 /* DESCRIPTION
@@ -42,6 +42,9 @@
 /*     Search the specified maps for \fIkey\fR and print the first value
 /*     found on the standard output stream. The exit status is non-zero
 /*     if the requested information was not found.
+/* .IP \fB-r\fR
+/*     When updating a table, do not warn about duplicate entries; silently
+/*     replace them.
 /* .IP \fB-v\fR
 /*     Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 /*     options make the software increasingly verbose.
@@ -332,7 +335,7 @@ static int postalias_delete(const char *map_type, const char *map_name,
 
 static NORETURN usage(char *myname)
 {
-    msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
+    msg_fatal("usage: %s [-Ninrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
              myname);
 }
 
@@ -382,7 +385,7 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "Nc:d:inq:vw")) > 0) {
+    while ((ch = GETOPT(argc, argv, "Nc:d:inq:rvw")) > 0) {
        switch (ch) {
        default:
            usage(argv[0]);
@@ -412,11 +415,15 @@ int     main(int argc, char **argv)
                msg_fatal("specify only one of -q or -d");
            query = optarg;
            break;
+       case 'r':
+           dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
+           dict_flags |= DICT_FLAG_DUP_REPLACE;
+           break;
        case 'v':
            msg_verbose++;
            break;
        case 'w':
-           dict_flags &= ~DICT_FLAG_DUP_WARN;
+           dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_REPLACE);
            dict_flags |= DICT_FLAG_DUP_IGNORE;
            break;
        }
index 3743bd971cc07349c586201cb965e9055967bd5c..da51ceb060cf583efb8494fe3e943ce84c99f3a7 100644 (file)
@@ -5,7 +5,7 @@
 /*     Postfix lookup table management
 /* SYNOPSIS
 /* .fi
-/*     \fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR]
+/*     \fBpostmap\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR]
 /*             [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
 /* DESCRIPTION
 /*     The \fBpostmap\fR command creates or queries one or more Postfix
@@ -60,6 +60,9 @@
 /*     Search the specified maps for \fIkey\fR and print the first value
 /*     found on the standard output stream. The exit status is non-zero
 /*     if the requested information was not found.
+/* .IP \fB-r\fR
+/*     When updating a table, do not warn about duplicate entries; silently
+/*     replace them.
 /* .IP \fB-v\fR
 /*     Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 /*     options make the software increasingly verbose.
@@ -285,7 +288,7 @@ static int postmap_delete(const char *map_type, const char *map_name,
 
 static NORETURN usage(char *myname)
 {
-    msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
+    msg_fatal("usage: %s [-Ninrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
              myname);
 }
 
@@ -335,7 +338,7 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "Nc:d:inq:vw")) > 0) {
+    while ((ch = GETOPT(argc, argv, "Nc:d:inq:rvw")) > 0) {
        switch (ch) {
        default:
            usage(argv[0]);
@@ -365,11 +368,15 @@ int     main(int argc, char **argv)
                msg_fatal("specify only one of -q or -d");
            query = optarg;
            break;
+       case 'r':
+           dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
+           dict_flags |= DICT_FLAG_DUP_REPLACE;
+           break;
        case 'v':
            msg_verbose++;
            break;
        case 'w':
-           dict_flags &= ~DICT_FLAG_DUP_WARN;
+           dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_REPLACE);
            dict_flags |= DICT_FLAG_DUP_IGNORE;
            break;
        }
index e7add092c7f901639ae11a644882d4d8b1c80799..0905cd58362a27b6b4ad66220d2f22ce1f1293ae 100644 (file)
 # .ti +5
 #      \fB\&.foo.org      error:mail for *.foo.org is not deliverable\fR
 #
-#      This causes all mail for \fIuser\fR@\fIanything\fBfoo.org\fR
+#      This causes all mail for \fIuser\fR@\fIanything\fB.foo.org\fR
 #      to be bounced.
 # REGULAR EXPRESSION TABLES
 # .ad
index 7508a8d8770373c08895432340a2f8c31fa0d4ba..374008e921903443f0911b9412e5f05dbdc16430 100644 (file)
@@ -477,7 +477,7 @@ int     main(int argc, char **argv)
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
-       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 0,
+       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 1000,
        VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0,
        VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 1, 0,
        VAR_INIT_DEST_CON, DEF_INIT_DEST_CON, &var_init_dest_concurrency, 1, 0,
index 7008cc7f35a74d345a7058bbd70eba09d75f77a1..c2167ce1955f4f0c1d228c902de2820fd8004d82 100644 (file)
@@ -199,6 +199,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
     long    save_offset = message->rcpt_offset;        /* save a flag */
     char   *start;
     struct stat st;
+    int     nrcpt;
 
     /*
      * Initialize. No early returns or we have a memory leak.
@@ -244,7 +245,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        start = vstring_str(buf);
        if (rec_type == REC_TYPE_SIZE) {
            if (message->data_size == 0)
-               message->data_size = atol(start);
+               sscanf(start, "%ld %ld %d",
+                      &message->data_size, &message->data_offset, &nrcpt);
        } else if (rec_type == REC_TYPE_TIME) {
            if (message->arrival_time == 0)
                message->arrival_time = atol(start);
@@ -258,7 +260,8 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
            if (message->sender == 0) {
                message->sender = mystrdup(start);
                opened(message->queue_id, message->sender,
-                      message->data_size, "queue %s", message->queue_name);
+                      message->data_size, nrcpt,
+                      "queue %s", message->queue_name);
            }
        } else if (rec_type == REC_TYPE_RCPT) {
 #define FUDGE(x)       ((x) * (var_qmgr_fudge / 100.0))
index 6d73cb4bab0d2974e7b93df88eee7f151725fe3b..f3b2ab7a0b919aac7bac3603eead7991cc869851 100644 (file)
@@ -387,6 +387,12 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
     } else {
        session = smtp_connect_domain(host, port, why);
     }
+    if (session == 0
+       && smtp_errno == SMTP_FAIL
+       && strcmp(host, var_relayhost) == 0) {
+       msg_warn("relayhost configuration problem: %s", var_relayhost);
+       smtp_errno = SMTP_RETRY;
+    }
     myfree(dest_buf);
     return (session);
 }
index 4d8701e4ff2fc484755234309278859499c7f385..765719bf5493253558b079136cb9f08f18e1035f 100644 (file)
 #include <smtp_stream.h>
 #include <valid_hostname.h>
 #include <dict.h>
+#include <watchdog.h>
 
 /* Global library. */
 
@@ -716,6 +717,8 @@ static void mail_reset(SMTPD_STATE *state)
 static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 {
     char   *err;
+    int     narg;
+    char   *arg;
 
     /*
      * Sanity checks.
@@ -725,7 +728,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "503 Error: need MAIL command");
        return (-1);
     }
-    if (argc != 3
+    if (argc < 3
        || strcasecmp(argv[1].strval, "to:") != 0) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
        smtpd_chat_reply(state, "501 Syntax: RCPT TO: <address>");
@@ -741,6 +744,14 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        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) {
        state->error_mask |= MAIL_ERROR_POLICY;
        smtpd_chat_reply(state, "452 Error: too many recipients");
@@ -1184,6 +1195,7 @@ static void smtpd_proto(SMTPD_STATE *state)
                smtpd_chat_reply(state, "421 Error: too many errors");
                break;
            }
+           watchdog_pat();
            smtpd_chat_query(state);
            if ((argc = smtpd_token(vstring_str(state->buffer), &argv)) == 0) {
                state->error_mask |= MAIL_ERROR_PROTOCOL;
index 65aca4fe1ad3dc548f2ee21fe6f2c802afedfbe1..f1669243af9bb17c2c0c7b55f9b5bfc6bf6b5fbb 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*++
 /* NAME
 /*     vstring 3
 /* SUMMARY
 /*     The function takes a VSTRING pointer and a list of zero
 /*     or more (name,value) pairs. The expected valye type of the
 /*     value depends on the specified name. The name codes are:
-/* .IP VSTRING_CTL_MAXLEN (int)
+/* .IP "VSTRING_CTL_MAXLEN (int)"
 /*     Specifies a hard upper limit on a string's length. When the
 /*     length would be exceeded, the program simulates a memory
 /*     allocation problem (i.e. it terminates through msg_fatal()).
-/* .IP VSTRING_CTL_END (no value)
+/* .IP "VSTRING_CTL_END (no value)"
 /*     Specifies the end of the argument list. Forgetting to terminate
 /*     the argument list may cause the program to crash.
 /* .PP
index da2ac106371c1b162f98d02569fd37481b12b2a3..011b2fcb60afe78c0c734a82848e3c5ef48e6853 100644 (file)
@@ -19,6 +19,8 @@
 /*
 /*     void    watchdog_destroy(watchdog)
 /*     WATCHDOG *watchdog;
+/*
+/*     void    watchdog_pat()
 /* DESCRIPTION
 /*     This module implements watchdog timers that are based on ugly
 /*     UNIX alarm timers. The module is designed to survive systems
@@ -39,6 +41,8 @@
 /*     watchdog_destroy() stops the watchdog timer, and resumes the
 /*     watchdog timer instance that was suspended by watchdog_create().
 /*
+/*     watchdog_pat() pats the watchdog, so it stays quiet.
+/*
 /*     Arguments:
 /* .IP timeout
 /*     The watchdog time limit. When the watchdog timer runs, the
@@ -213,6 +217,18 @@ void    watchdog_stop(WATCHDOG *wp)
        msg_info("%s: %p", myname, (char *) wp);
 }
 
+/* watchdog_pat - pat the dog so it stays quiet */
+
+void    watchdog_pat(void)
+{
+    char   *myname = "watchdog_pat";
+
+    if (watchdog_curr)
+       watchdog_curr->trip_run = 0;
+    if (msg_verbose)
+       msg_info("%s: %p", myname, (char *) watchdog_curr);
+}
+
 #ifdef TEST
 
 #include <vstream.h>
@@ -224,8 +240,9 @@ main(int unused_argc, char **unused_argv)
     msg_verbose = 1;
 
     wp = watchdog_create(10, (WATCHDOG_FN) 0, (char *) 0);
+    watchdog_start(wp);
     do {
-       watchdog_start(wp);
+       watchdog_pat();
     } while (VSTREAM_GETCHAR() != VSTREAM_EOF);
     watchdog_destroy(wp);
 }
index 926233b69f0d3c22a86732bcf6990915b254d98e..ee01faf9f8134945bf1d92a828afe94a44373158 100644 (file)
@@ -20,6 +20,7 @@ extern WATCHDOG *watchdog_create(unsigned, WATCHDOG_FN, char *);
 extern void watchdog_start(WATCHDOG *);
 extern void watchdog_stop(WATCHDOG *);
 extern void watchdog_destroy(WATCHDOG *);
+extern void watchdog_pat(void);
 
 /* LICENSE
 /* .ad