From: Wietse Venema
+Postfix version 2.1 and later:
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
diff --git a/postfix/html/access.5.html b/postfix/html/access.5.html
index f73bc3bef..1eb182bbc 100644
--- a/postfix/html/access.5.html
+++ b/postfix/html/access.5.html
@@ -225,6 +225,17 @@ ACCESS(5) ACCESS(5)
Apply the named UCE restriction(s) (permit, reject,
reject_unauth_destination, and so on).
+ BCC user@domain
+ Send one copy of the message to the specified
+ recipient.
+
+ If multiple BCC actions are specified within the
+ same SMTP MAIL transaction, only the last action
+ will be used.
+
+ This feature is not part of the stable Postfix
+ release.
+
DISCARD optional text...
Claim successful delivery and silently discard the
message. Log the optional text if specified, oth-
diff --git a/postfix/html/pcre_table.5.html b/postfix/html/pcre_table.5.html
index 7a68ce8a5..a80d3108e 100644
--- a/postfix/html/pcre_table.5.html
+++ b/postfix/html/pcre_table.5.html
@@ -50,8 +50,8 @@ PCRE_TABLE(5) PCRE_TABLE(5)
if /pattern/flags
endif Match the input string against the patterns between
- if and endif, if and only if the input string also
- matches pattern. The if..endif can nest.
+ if and endif, if and only if that same input string
+ also matches pattern. The if..endif can nest.
Note: do not prepend whitespace to patterns inside
if..endif.
@@ -61,8 +61,8 @@ PCRE_TABLE(5) PCRE_TABLE(5)
if !/pattern/flags
endif Match the input string against the patterns between
- if and endif, if and only if the input string does
- not match pattern. The if..endif can nest.
+ if and endif, if and only if that same input string
+ does not match pattern. The if..endif can nest.
Note: do not prepend whitespace to patterns inside
if..endif.
diff --git a/postfix/html/pipe.8.html b/postfix/html/pipe.8.html
index a6abe8188..cf1210a0c 100644
--- a/postfix/html/pipe.8.html
+++ b/postfix/html/pipe.8.html
@@ -30,9 +30,11 @@ PIPE(8) PIPE(8)
trace(8) daemon as appropriate.
SINGLE-RECIPIENT DELIVERY
- Some external commands cannot handle more than one recipi-
- ent per delivery request. Examples of such transports are
- pagers or fax machines.
+ Some destinations cannot handle more than one recipient
+ per delivery request. Examples are pagers or fax machines.
+ In addition, multi-recipient delivery is undesirable when
+ prepending a Delivered-to: or X-Original-To: message
+ header.
To prevent Postfix from sending multiple recipients per
delivery request, specify
@@ -86,89 +88,99 @@ PIPE(8) PIPE(8)
D Prepend a "Delivered-To: recipient" message
header with the envelope recipient address.
Note: for this to work, the transport_desti-
- nation_recipient_limit must be 1.
+ nation_recipient_limit must be 1 (see SIN-
+ GLE-RECIPIENT DELIVERY above for details).
+
+ This code also enforces loop detection
+ (Postfix 2.5 and later). If a message
+ already contains a Delivered-To: header with
+ the same recipient address, then the message
+ is returned as undeliverable.
This feature is available as of Postfix 2.0.
- F Prepend a "From sender time_stamp" envelope
- header to the message content. This is
+ F Prepend a "From sender time_stamp" envelope
+ header to the message content. This is
expected by, for example, UUCP software.
- O Prepend an "X-Original-To: recipient" mes-
- sage header with the recipient address as
- given to Postfix. Note: for this to work,
+ O Prepend an "X-Original-To: recipient" mes-
+ sage header with the recipient address as
+ given to Postfix. Note: for this to work,
the transport_destination_recipient_limit
- must be 1.
+ must be 1 (see SINGLE-RECIPIENT DELIVERY
+ above for details).
This feature is available as of Postfix 2.0.
R Prepend a Return-Path: message header with
the envelope sender address.
- h Fold the command-line $recipient domain name
- and $nexthop host name to lower case. This
- is recommended for delivery via UUCP.
+ h Fold the command-line $recipient address
+ domain part (text to the right of the right-
+ most @ character) to lower case; fold the
+ entire command-line $domain and $nexthop
+ host or domain information to lower case.
+ This is recommended for delivery via UUCP.
- q Quote white space and other special charac-
+ q Quote white space and other special charac-
ters in the command-line $sender and $recip-
ient address localparts (text to the left of
the right-most @ character), according to an
- 8-bit transparent version of RFC 822. This
- is recommended for delivery via UUCP or
+ 8-bit transparent version of RFC 822. This
+ is recommended for delivery via UUCP or
BSMTP.
- The result is compatible with the address
- parsing of command-line recipients by the
+ The result is compatible with the address
+ parsing of command-line recipients by the
Postfix sendmail(1) mail submission command.
- The q flag affects only entire addresses,
+ The q flag affects only entire addresses,
not the partial address information from the
- $user, $extension or $mailbox command-line
+ $user, $extension or $mailbox command-line
macros.
u Fold the command-line $recipient address
- localpart (text to the left of the right-
- most @ character) to lower case. This is
+ localpart (text to the left of the right-
+ most @ character) to lower case. This is
recommended for delivery via UUCP.
. Prepend "." to lines starting with ".". This
is needed by, for example, BSMTP software.
- > Prepend ">" to lines starting with "From ".
+ > Prepend ">" to lines starting with "From ".
This is expected by, for example, UUCP soft-
ware.
null_sender=replacement (default: MAILER-DAEMON)
Replace the null sender address (typically used for
- delivery status notifications) with the specified
+ delivery status notifications) with the specified
text when expanding the $sender command-line macro,
and when generating a From_ or Return-Path: message
header.
- If the null sender replacement text is a non-empty
- string then it is affected by the q flag for
+ If the null sender replacement text is a non-empty
+ string then it is affected by the q flag for
address quoting in command-line arguments.
The null sender replacement text may be empty; this
- form is recommended for content filters that feed
+ form is recommended for content filters that feed
mail back into Postfix. The empty sender address is
- not affected by the q flag for address quoting in
+ not affected by the q flag for address quoting in
command-line arguments.
Caution: a null sender address is easily mis-parsed
- by naive software. For example, when the pipe(8)
+ by naive software. For example, when the pipe(8)
daemon executes a command such as:
command -f$sender -- $recipient (bad)
the command will mis-parse the -f option value when
- the sender address is a null string. For correct
+ the sender address is a null string. For correct
parsing, specify $sender as an argument by itself:
command -f $sender -- $recipient (good)
- This feature is available with Postfix 2.3 and
- later.
+ This feature is available as of Postfix 2.3.
size=size_limit (optional)
Messages greater in size than this limit (in bytes)
@@ -224,176 +236,187 @@ PIPE(8) PIPE(8)
This is available in Postfix 2.2 and later.
+ ${domain}
+ This macro expands to the domain portion of
+ the recipient address. For example, with an
+ address user+foo@domain the domain is
+ domain.
+
+ This information is modified by the h flag
+ for case folding.
+
+ This is available in Postfix 2.5 and later.
+
${extension}
- This macro expands to the extension part of
- a recipient address. For example, with an
+ This macro expands to the extension part of
+ a recipient address. For example, with an
address user+foo@domain the extension is
foo.
- A command-line argument that contains
- ${extension} expands into as many command-
+ A command-line argument that contains
+ ${extension} expands into as many command-
line arguments as there are recipients.
- This information is modified by the u flag
+ This information is modified by the u flag
for case folding.
${mailbox}
- This macro expands to the complete local
- part of a recipient address. For example,
- with an address user+foo@domain the mailbox
+ This macro expands to the complete local
+ part of a recipient address. For example,
+ with an address user+foo@domain the mailbox
is user+foo.
- A command-line argument that contains
- ${mailbox} expands to as many command-line
+ A command-line argument that contains
+ ${mailbox} expands to as many command-line
arguments as there are recipients.
- This information is modified by the u flag
+ This information is modified by the u flag
for case folding.
${nexthop}
This macro expands to the next-hop hostname.
- This information is modified by the h flag
+ This information is modified by the h flag
for case folding.
${recipient}
This macro expands to the complete recipient
address.
- A command-line argument that contains
+ A command-line argument that contains
${recipient} expands to as many command-line
arguments as there are recipients.
- This information is modified by the hqu
+ This information is modified by the hqu
flags for quoting and case folding.
${sasl_method}
- This macro expands to the SASL authentica-
- tion mechanism used during the reception of
- the message. An empty string is passed if
- the message has been received without SASL
+ This macro expands to the SASL authentica-
+ tion mechanism used during the reception of
+ the message. An empty string is passed if
+ the message has been received without SASL
authentication.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
${sasl_sender}
- This macro expands to the SASL sender name
- (i.e. the original submitter as per RFC
- 2554) used during the reception of the mes-
+ This macro expands to the SASL sender name
+ (i.e. the original submitter as per RFC
+ 2554) used during the reception of the mes-
sage.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
${sasl_username}
- This macro expands to the SASL user name
+ This macro expands to the SASL user name
used during the reception of the message. An
- empty string is passed if the message has
+ empty string is passed if the message has
been received without SASL authentication.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
${sender}
- This macro expands to the envelope sender
+ This macro expands to the envelope sender
address. By default, the null sender address
- expands to MAILER-DAEMON; this can be
- changed with the null_sender attribute, as
+ expands to MAILER-DAEMON; this can be
+ changed with the null_sender attribute, as
described above.
- This information is modified by the q flag
+ This information is modified by the q flag
for quoting.
${size}
- This macro expands to Postfix's idea of the
- message size, which is an approximation of
+ This macro expands to Postfix's idea of the
+ message size, which is an approximation of
the size of the message as delivered.
${user}
This macro expands to the username part of a
- recipient address. For example, with an
+ recipient address. For example, with an
address user+foo@domain the username part is
user.
- A command-line argument that contains
- ${user} expands into as many command-line
+ A command-line argument that contains
+ ${user} expands into as many command-line
arguments as there are recipients.
- This information is modified by the u flag
+ This information is modified by the u flag
for case folding.
STANDARDS
RFC 3463 (Enhanced status codes)
DIAGNOSTICS
- Command exit status codes are expected to follow the con-
- ventions defined in <sysexits.h>. Exit status 0 means
+ Command exit status codes are expected to follow the con-
+ ventions defined in <sysexits.h>. Exit status 0 means
normal successful completion.
- Postfix version 2.3 and later support RFC 3463-style
- enhanced status codes. If a command terminates with a
- non-zero exit status, and the command output begins with
+ Postfix version 2.3 and later support RFC 3463-style
+ enhanced status codes. If a command terminates with a
+ non-zero exit status, and the command output begins with
an enhanced status code, this status code takes precedence
over the non-zero exit status.
- Problems and transactions are logged to syslogd(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to syslogd(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the corrupt queue for further inspection.
SECURITY
- This program needs a dual personality 1) to access the
- private Postfix queue and IPC mechanisms, and 2) to exe-
+ This program needs a dual personality 1) to access the
+ private Postfix queue and IPC mechanisms, and 2) to exe-
cute external commands as the specified user. It is there-
fore security sensitive.
CONFIGURATION PARAMETERS
- Changes to main.cf are picked up automatically as pipe(8)
- processes run for only a limited amount of time. Use the
+ Changes to main.cf are picked up automatically as pipe(8)
+ processes run for only a limited amount of time. Use the
command "postfix reload" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
postconf(5) for more details including examples.
RESOURCE AND RATE CONTROLS
- In the text below, transport is the first field in a mas-
+ In the text below, transport is the first field in a mas-
ter.cf entry.
transport_destination_concurrency_limit ($default_destina-
tion_concurrency_limit)
Limit the number of parallel deliveries to the same
- destination, for delivery via the named transport.
+ destination, for delivery via the named transport.
The limit is enforced by the Postfix queue manager.
transport_destination_recipient_limit ($default_destina-
tion_recipient_limit)
- Limit the number of recipients per message deliv-
- ery, for delivery via the named transport. The
+ Limit the number of recipients per message deliv-
+ ery, for delivery via the named transport. The
limit is enforced by the Postfix queue manager.
transport_time_limit ($command_time_limit)
- Limit the time for delivery to external command,
+ Limit the time for delivery to external command,
for delivery via the named transport. The limit is
enforced by the pipe delivery agent.
- Postfix 2.4 and later support a suffix that speci-
- fies the time unit: s (seconds), m (minutes), h
+ Postfix 2.4 and later support a suffix that speci-
+ fies the time unit: s (seconds), m (minutes), h
(hours), d (days), w (weeks). The default time unit
is seconds.
MISCELLANEOUS CONTROLS
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
daemon_timeout (18000s)
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
delay_logging_resolution_limit (2)
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
export_environment (see 'postconf -d' output)
- The list of environment variables that a Postfix
+ The list of environment variables that a Postfix
process will export to non-Postfix processes.
ipc_timeout (3600s)
@@ -405,25 +428,25 @@ PIPE(8) PIPE(8)
and most Postfix daemon processes.
max_idle (100s)
- The maximum amount of time that an idle Postfix
- daemon process waits for an incoming connection
+ The maximum amount of time that an idle Postfix
+ daemon process waits for an incoming connection
before terminating voluntarily.
max_use (100)
- The maximal number of incoming connections that a
- Postfix daemon process will service before termi-
+ The maximal number of incoming connections that a
+ Postfix daemon process will service before termi-
nating voluntarily.
process_id (read-only)
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
process_name (read-only)
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
queue_directory (see 'postconf -d' output)
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
recipient_delimiter (empty)
@@ -434,8 +457,8 @@ PIPE(8) PIPE(8)
The syslog facility of Postfix logging.
syslog_name (postfix)
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
SEE ALSO
@@ -447,7 +470,7 @@ PIPE(8) PIPE(8)
syslogd(8), system logging
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/html/regexp_table.5.html b/postfix/html/regexp_table.5.html
index ac0646f7a..5ec01696f 100644
--- a/postfix/html/regexp_table.5.html
+++ b/postfix/html/regexp_table.5.html
@@ -62,77 +62,76 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
endif Match the input string against the patterns between
if and endif, if and only if that same input string
- does not match pattern. The if..endif can nest.
- matches pattern. The if..endif can nest.
+ does not match pattern. The if..endif can nest.
- Note: do not prepend whitespace to patterns inside
+ Note: do not prepend whitespace to patterns inside
if..endif.
This feature is available in Postfix 2.1 and later.
blank lines and comments
- Empty lines and whitespace-only lines are ignored,
- as are lines whose first non-whitespace character
+ Empty lines and whitespace-only lines are ignored,
+ as are lines whose first non-whitespace character
is a `#'.
multi-line text
- A logical line starts with non-whitespace text. A
- line that starts with whitespace continues a logi-
+ A logical line starts with non-whitespace text. A
+ line that starts with whitespace continues a logi-
cal line.
- Each pattern is a POSIX regular expression enclosed by a
+ Each pattern is a POSIX regular expression enclosed by a
pair of delimiters. The regular expression syntax is docu-
- mented in re_format(7) with 4.4BSD, in regex(5) with
+ mented in re_format(7) with 4.4BSD, in regex(5) with
Solaris, and in regex(7) with Linux. Other systems may use
other document names.
- The expression delimiter can be any character, except
+ The expression delimiter can be any character, except
whitespace or characters that have special meaning (tradi-
- tionally the forward slash is used). The regular expres-
+ tionally the forward slash is used). The regular expres-
sion can contain whitespace.
By default, matching is case-insensitive, and newlines are
- not treated as special characters. The behavior is con-
- trolled by flags, which are toggled by appending one or
+ not treated as special characters. The behavior is con-
+ trolled by flags, which are toggled by appending one or
more of the following characters after the pattern:
i (default: on)
- Toggles the case sensitivity flag. By default,
+ Toggles the case sensitivity flag. By default,
matching is case insensitive.
x (default: on)
- Toggles the extended expression syntax flag. By
- default, support for extended expression syntax is
+ Toggles the extended expression syntax flag. By
+ default, support for extended expression syntax is
enabled.
m (default: off)
- Toggle the multi-line mode flag. When this flag is
- on, the ^ and $ metacharacters match immediately
- after and immediately before a newline character,
- respectively, in addition to matching at the start
+ Toggle the multi-line mode flag. When this flag is
+ on, the ^ and $ metacharacters match immediately
+ after and immediately before a newline character,
+ respectively, in addition to matching at the start
and end of the input string.
TABLE SEARCH ORDER
- Patterns are applied in the order as specified in the ta-
- ble, until a pattern is found that matches the input
+ Patterns are applied in the order as specified in the ta-
+ ble, until a pattern is found that matches the input
string.
- Each pattern is applied to the entire input string.
- Depending on the application, that string is an entire
+ Each pattern is applied to the entire input string.
+ Depending on the application, that string is an entire
client hostname, an entire client IP address, or an entire
- mail address. Thus, no parent domain or parent network
- search is done, and user@domain mail addresses are not
- broken up into their user and domain constituent parts,
+ mail address. Thus, no parent domain or parent network
+ search is done, and user@domain mail addresses are not
+ broken up into their user and domain constituent parts,
nor is user+foo broken up into user and foo.
TEXT SUBSTITUTION
- Substitution of substrings from the matched expression
- into the result string is possible using $1, $2, etc.;
+ Substitution of substrings from the matched expression
+ into the result string is possible using $1, $2, etc.;
specify $$ to produce a $ character as output. The macros
- in the result string may need to be written as ${n} or
+ in the result string may need to be written as ${n} or
$(n) if they aren't followed by whitespace.
- Note: since negated patterns (those preceded by !) return
+ Note: since negated patterns (those preceded by !) return
a result when the expression does not match, substitutions
are not available for negated patterns.
diff --git a/postfix/man/man5/access.5 b/postfix/man/man5/access.5
index 63485b9f5..e96f4ad3b 100644
--- a/postfix/man/man5/access.5
+++ b/postfix/man/man5/access.5
@@ -216,6 +216,13 @@ This feature is available in Postfix 2.1 and later.
.IP \fIrestriction...\fR
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
\fBreject_unauth_destination\fR, and so on).
+.IP "\fBBCC \fIuser@domain\fR"
+Send one copy of the message to the specified recipient.
+.sp
+If multiple BCC actions are specified within the same SMTP
+MAIL transaction, only the last action will be used.
+.sp
+This feature is not part of the stable Postfix release.
.IP "\fBDISCARD \fIoptional text...\fR
Claim successful delivery and silently discard the message.
Log the optional text if specified, otherwise log a generic
diff --git a/postfix/man/man5/pcre_table.5 b/postfix/man/man5/pcre_table.5
index 8cb6abf5d..c3c008fb1 100644
--- a/postfix/man/man5/pcre_table.5
+++ b/postfix/man/man5/pcre_table.5
@@ -51,7 +51,7 @@ the corresponding \fIresult\fR value.
.IP "\fBif /\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR
-and \fBendif\fR, if and only if the input string also matches
+and \fBendif\fR, if and only if that same input string also matches
\fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
@@ -61,7 +61,7 @@ This feature is available in Postfix 2.1 and later.
.IP "\fBif !/\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR
-and \fBendif\fR, if and only if the input string does \fBnot\fR
+and \fBendif\fR, if and only if that same input string does \fBnot\fR
match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
diff --git a/postfix/man/man5/regexp_table.5 b/postfix/man/man5/regexp_table.5
index 5113c1a1f..4b4d98231 100644
--- a/postfix/man/man5/regexp_table.5
+++ b/postfix/man/man5/regexp_table.5
@@ -63,7 +63,6 @@ This feature is available in Postfix 2.1 and later.
Match the input string against the patterns between \fBif\fR
and \fBendif\fR, if and only if that same input string does
\fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
-matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR.
diff --git a/postfix/man/man8/pipe.8 b/postfix/man/man8/pipe.8
index 4c27e7bb0..7b5a2c675 100644
--- a/postfix/man/man8/pipe.8
+++ b/postfix/man/man8/pipe.8
@@ -31,9 +31,11 @@ appropriate.
.nf
.ad
.fi
-Some external commands cannot handle more than one recipient
-per delivery request. Examples of such transports are pagers
-or fax machines.
+Some destinations cannot handle more than one recipient per
+delivery request. Examples are pagers or fax machines.
+In addition, multi-recipient delivery is undesirable when
+prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
+message header.
To prevent Postfix from sending multiple recipients per delivery
request, specify
@@ -84,7 +86,13 @@ when preceded by a blank line.
.IP \fBD\fR
Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
envelope recipient address. Note: for this to work, the
-\fItransport\fB_destination_recipient_limit\fR must be 1.
+\fItransport\fB_destination_recipient_limit\fR must be 1
+(see SINGLE-RECIPIENT DELIVERY above for details).
+.sp
+This code also enforces loop detection (Postfix 2.5 and later).
+If a message already contains a \fBDelivered-To:\fR header
+with the same recipient address, then the message is
+returned as undeliverable.
.sp
This feature is available as of Postfix 2.0.
.IP \fBF\fR
@@ -94,15 +102,18 @@ This is expected by, for example, \fBUUCP\fR software.
.IP \fBO\fR
Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
with the recipient address as given to Postfix. Note: for this to
-work, the \fItransport\fB_destination_recipient_limit\fR must be 1.
+work, the \fItransport\fB_destination_recipient_limit\fR must be 1
+(see SINGLE-RECIPIENT DELIVERY above for details).
.sp
This feature is available as of Postfix 2.0.
.IP \fBR\fR
Prepend a \fBReturn-Path:\fR message header with the envelope sender
address.
.IP \fBh\fR
-Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
-host name to lower case.
+Fold the command-line \fB$recipient\fR address domain part
+(text to the right of the right-most \fB@\fR character) to
+lower case; fold the entire command-line \fB$domain\fR and
+\fB$nexthop\fR host or domain information to lower case.
This is recommended for delivery via \fBUUCP\fR.
.IP \fBq\fR
Quote white space and other special characters in the command-line
@@ -159,7 +170,7 @@ specify \fB$sender\fR as an argument by itself:
command -f $sender -- $recipient (\fIgood\fR)
.fi
.IP
-This feature is available with Postfix 2.3 and later.
+This feature is available as of Postfix 2.3.
.IP "\fBsize\fR=\fIsize_limit\fR (optional)"
Messages greater in size than this limit (in bytes) will
be returned to the sender as undeliverable.
@@ -201,6 +212,14 @@ This is available in Postfix 2.2 and later.
This macro expands to the remote client protocol.
.sp
This is available in Postfix 2.2 and later.
+.IP \fB${\fBdomain\fR}\fR
+This macro expands to the domain portion of the recipient
+address. For example, with an address \fIuser+foo@domain\fR
+the domain is \fIdomain\fR.
+.sp
+This information is modified by the \fBh\fR flag for case folding.
+.sp
+This is available in Postfix 2.5 and later.
.IP \fB${\fBextension\fR}\fR
This macro expands to the extension part of a recipient address.
For example, with an address \fIuser+foo@domain\fR the extension is
diff --git a/postfix/proto/SMTPD_POLICY_README.html b/postfix/proto/SMTPD_POLICY_README.html
index b0fc39ee3..1854a6f00 100644
--- a/postfix/proto/SMTPD_POLICY_README.html
+++ b/postfix/proto/SMTPD_POLICY_README.html
@@ -74,6 +74,7 @@ server sends in a delegated SMTPD access policy request:
+Postfix version 2.1 and later:
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
diff --git a/postfix/proto/access b/postfix/proto/access
index 6ebee10ad..665cc9e8f 100644
--- a/postfix/proto/access
+++ b/postfix/proto/access
@@ -194,6 +194,13 @@
# .IP \fIrestriction...\fR
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
# \fBreject_unauth_destination\fR, and so on).
+# .IP "\fBBCC \fIuser@domain\fR"
+# Send one copy of the message to the specified recipient.
+# .sp
+# If multiple BCC actions are specified within the same SMTP
+# MAIL transaction, only the last action will be used.
+# .sp
+# This feature is not part of the stable Postfix release.
# \" .IP "\fBDELAY \fItime\fR"
# \" Place the message into the deferred queue, and delay the
# \" initial delivery attempt by \fItime\fR. The time value may
diff --git a/postfix/proto/pcre_table b/postfix/proto/pcre_table
index c0ab8f3eb..679e67ef7 100644
--- a/postfix/proto/pcre_table
+++ b/postfix/proto/pcre_table
@@ -41,7 +41,7 @@
# .IP "\fBif /\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR
-# and \fBendif\fR, if and only if the input string also matches
+# and \fBendif\fR, if and only if that same input string also matches
# \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
@@ -51,7 +51,7 @@
# .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR
-# and \fBendif\fR, if and only if the input string does \fBnot\fR
+# and \fBendif\fR, if and only if that same input string does \fBnot\fR
# match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
diff --git a/postfix/proto/regexp_table b/postfix/proto/regexp_table
index 3a15f46a9..6e225b33c 100644
--- a/postfix/proto/regexp_table
+++ b/postfix/proto/regexp_table
@@ -53,7 +53,6 @@
# Match the input string against the patterns between \fBif\fR
# and \fBendif\fR, if and only if that same input string does
# \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
-# matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR.
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index b6c602f0b..1e2aa89a2 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -27,7 +27,7 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c \
user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \
- verp_sender.c wildcard_inet_addr.c xtext.c
+ verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -56,7 +56,7 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o \
user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \
- verp_sender.o wildcard_inet_addr.o xtext.o
+ verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -79,7 +79,7 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
rewrite_clnt.h scache.h sent.h smtp_stream.h split_addr.h \
string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \
- verp_sender.h wildcard_inet_addr.h xtext.h
+ verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -688,6 +688,23 @@ deliver_request.o: mail_queue.h
deliver_request.o: msg_stats.h
deliver_request.o: rcpt_buf.h
deliver_request.o: recipient_list.h
+delivered_hdr.o: ../../include/htable.h
+delivered_hdr.o: ../../include/msg.h
+delivered_hdr.o: ../../include/mymalloc.h
+delivered_hdr.o: ../../include/stringops.h
+delivered_hdr.o: ../../include/sys_defs.h
+delivered_hdr.o: ../../include/vbuf.h
+delivered_hdr.o: ../../include/vstream.h
+delivered_hdr.o: ../../include/vstring.h
+delivered_hdr.o: ../../include/vstring_vstream.h
+delivered_hdr.o: delivered_hdr.c
+delivered_hdr.o: delivered_hdr.h
+delivered_hdr.o: header_opts.h
+delivered_hdr.o: is_header.h
+delivered_hdr.o: quote_822_local.h
+delivered_hdr.o: quote_flags.h
+delivered_hdr.o: rec_type.h
+delivered_hdr.o: record.h
dict_ldap.o: ../../include/argv.h
dict_ldap.o: ../../include/binhash.h
dict_ldap.o: ../../include/dict.h
diff --git a/postfix/src/global/delivered_hdr.c b/postfix/src/global/delivered_hdr.c
new file mode 100644
index 000000000..f3dc2c4d5
--- /dev/null
+++ b/postfix/src/global/delivered_hdr.c
@@ -0,0 +1,167 @@
+/*++
+/* NAME
+/* delivered_hdr 3
+/* SUMMARY
+/* process Delivered-To: headers
+/* SYNOPSIS
+/* #include
+/*
+/* DELIVERED_HDR_INFO *delivered_hdr_init(stream, offset)
+/* VSTREAM *stream;
+/* off_t offset;
+/*
+/* int delivered_hdr_find(info, address)
+/* DELIVERED_HDR_INFO *info;
+/* const char *address;
+/*
+/* void delivered_hdr_free(info)
+/* DELIVERED_HDR_INFO *info;
+/* DESCRIPTION
+/* This module processes addresses in Delivered-To: headers.
+/* These headers are added by some mail delivery systems, for the
+/* purpose of breaking mail forwarding loops. N.B. This solves
+/* a different problem than the Received: hop count limit. Hop
+/* counts are used to limit the impact of mail routing problems.
+/*
+/* delivered_hdr_init() extracts Delivered-To: header addresses
+/* from the specified message, and returns a table with the
+/* result. The file seek pointer is changed.
+/*
+/* delivered_hdr_find() looks up the address in the lookup table,
+/* and returns non-zero when the address was found. The
+/* address argument must be in internalized form.
+/*
+/* delivered_hdr_free() releases storage that was allocated by
+/* delivered_hdr_init().
+/*
+/* Arguments:
+/* .IP stream
+/* The open queue file.
+/* .IP offset
+/* Offset of the first message content record.
+/* .IP info
+/* Extracted Delivered-To: addresses information.
+/* .IP address
+/* A recipient address, internal form.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory.
+/* SEE ALSO
+/* mail_copy(3), producer of Delivered-To: and other headers.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Global library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+ /*
+ * Application-specific.
+ */
+struct DELIVERED_HDR_INFO {
+ VSTRING *buf;
+ HTABLE *table;
+};
+
+#define STR(x) vstring_str(x)
+
+/* delivered_hdr_init - extract delivered-to information from the message */
+
+DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset)
+{
+ char *cp;
+ DELIVERED_HDR_INFO *info;
+ HEADER_OPTS *hdr;
+
+ info = (DELIVERED_HDR_INFO *) mymalloc(sizeof(*info));
+ info->buf = vstring_alloc(10);
+ info->table = htable_create(0);
+
+ if (vstream_fseek(fp, offset, SEEK_SET) < 0)
+ msg_fatal("seek queue file %s: %m", VSTREAM_PATH(fp));
+
+ /*
+ * XXX Assume that mail_copy() produces delivered-to headers that fit in
+ * a REC_TYPE_NORM record. Lowercase the delivered-to addresses for
+ * consistency.
+ *
+ * XXX Don't get bogged down by gazillions of delivered-to headers.
+ */
+#define DELIVERED_HDR_LIMIT 1000
+
+ while (rec_get(fp, info->buf, 0) == REC_TYPE_NORM
+ && info->table->used < DELIVERED_HDR_LIMIT) {
+ if (is_header(STR(info->buf))) {
+ if ((hdr = header_opts_find(STR(info->buf))) != 0
+ && hdr->type == HDR_DELIVERED_TO) {
+ cp = STR(info->buf) + strlen(hdr->name) + 1;
+ while (ISSPACE(*cp))
+ cp++;
+ lowercase(cp);
+ if (msg_verbose)
+ msg_info("delivered_hdr_init: %s", cp);
+ htable_enter(info->table, cp, (char *) 0);
+ }
+ } else if (ISSPACE(STR(info->buf)[0])) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ return (info);
+}
+
+/* delivered_hdr_find - look up recipient in delivered table */
+
+int delivered_hdr_find(DELIVERED_HDR_INFO *info, const char *address)
+{
+ HTABLE_INFO *ht;
+
+ /*
+ * mail_copy() uses quote_822_local() when writing the Delivered-To:
+ * header. We must therefore apply the same transformation when looking
+ * up the recipient. Lowercase the delivered-to address for consistency.
+ */
+ quote_822_local(info->buf, address);
+ lowercase(STR(info->buf));
+ ht = htable_locate(info->table, STR(info->buf));
+ return (ht != 0);
+}
+
+/* delivered_hdr_free - destructor */
+
+void delivered_hdr_free(DELIVERED_HDR_INFO *info)
+{
+ vstring_free(info->buf);
+ htable_free(info->table, (void (*) (char *)) 0);
+ myfree((char *) info);
+}
diff --git a/postfix/src/global/delivered_hdr.h b/postfix/src/global/delivered_hdr.h
new file mode 100644
index 000000000..4a7ca25b7
--- /dev/null
+++ b/postfix/src/global/delivered_hdr.h
@@ -0,0 +1,38 @@
+#ifndef _DELIVERED_HDR_H_INCLUDED_
+#define _DELIVERED_HDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* delivered_hdr 3h
+/* SUMMARY
+/* process Delivered-To: headers
+/* SYNOPSIS
+/* #include
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include
+
+ /*
+ * External interface.
+ */
+typedef struct DELIVERED_HDR_INFO DELIVERED_HDR_INFO;
+extern DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *, off_t);
+extern int delivered_hdr_find(DELIVERED_HDR_INFO *, const char *);
+extern void delivered_hdr_free(DELIVERED_HDR_INFO *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index da7a1f3d3..b5f4ec0d8 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070402"
+#define MAIL_RELEASE_DATE "20070422"
#define MAIL_VERSION_NUMBER "2.5"
#ifdef SNAPSHOT
diff --git a/postfix/src/global/resolve_clnt.c b/postfix/src/global/resolve_clnt.c
index b96f0a736..4668deadd 100644
--- a/postfix/src/global/resolve_clnt.c
+++ b/postfix/src/global/resolve_clnt.c
@@ -141,6 +141,7 @@
*/
extern CLNT_STREAM *rewrite_clnt_stream;
+static time_t last_expire;
static VSTRING *last_class;
static VSTRING *last_sender;
static VSTRING *last_addr;
@@ -190,7 +191,8 @@ void resolve_clnt(const char *class, const char *sender,
*/
#define IFSET(flag, text) ((reply->flags & (flag)) ? (text) : "")
- if (*addr && strcmp(addr, STR(last_addr)) == 0
+ if (event_time() < last_expire
+ && *addr && strcmp(addr, STR(last_addr)) == 0
&& strcmp(class, STR(last_class)) == 0
&& strcmp(sender, STR(last_sender)) == 0) {
vstring_strcpy(reply->transport, STR(last_reply.transport));
@@ -282,6 +284,7 @@ void resolve_clnt(const char *class, const char *sender,
vstring_strcpy(last_reply.nexthop, STR(reply->nexthop));
vstring_strcpy(last_reply.recipient, STR(reply->recipient));
last_reply.flags = reply->flags;
+ last_expire = event_time() + 30; /* XXX make configurable */
}
/* resolve_clnt_free - destroy reply */
diff --git a/postfix/src/global/rewrite_clnt.c b/postfix/src/global/rewrite_clnt.c
index 8bb3f0a52..6d110bf59 100644
--- a/postfix/src/global/rewrite_clnt.c
+++ b/postfix/src/global/rewrite_clnt.c
@@ -72,6 +72,7 @@
*/
CLNT_STREAM *rewrite_clnt_stream = 0;
+static time_t last_expire;
static VSTRING *last_rule;
static VSTRING *last_addr;
static VSTRING *last_result;
@@ -107,7 +108,8 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
/*
* Peek at the cache.
*/
- if (strcmp(addr, STR(last_addr)) == 0
+ if (event_time() < last_expire
+ && strcmp(addr, STR(last_addr)) == 0
&& strcmp(rule, STR(last_rule)) == 0) {
vstring_strcpy(result, STR(last_result));
if (msg_verbose)
@@ -163,6 +165,7 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
vstring_strcpy(last_rule, rule);
vstring_strcpy(last_addr, addr);
vstring_strcpy(last_result, STR(result));
+ last_expire = event_time() + 30; /* XXX make configurable */
return (result);
}
diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in
index f22a5646e..10962b5cc 100644
--- a/postfix/src/local/Makefile.in
+++ b/postfix/src/local/Makefile.in
@@ -1,9 +1,9 @@
SHELL = /bin/sh
-SRCS = alias.c command.c delivered.c dotforward.c file.c forward.c \
+SRCS = alias.c command.c dotforward.c file.c forward.c \
include.c indirect.c local.c mailbox.c recipient.c resolve.c token.c \
deliver_attr.c maildir.c biff_notify.c unknown.c \
local_expand.c
-OBJS = alias.o command.o delivered.o dotforward.o file.o forward.o \
+OBJS = alias.o command.o dotforward.o file.o forward.o \
include.o indirect.o local.o mailbox.o recipient.o resolve.o token.o \
deliver_attr.o maildir.o biff_notify.o unknown.o \
local_expand.o
@@ -71,6 +71,7 @@ alias.o: ../../include/bounce.h
alias.o: ../../include/canon_addr.h
alias.o: ../../include/defer.h
alias.o: ../../include/deliver_request.h
+alias.o: ../../include/delivered_hdr.h
alias.o: ../../include/dict.h
alias.o: ../../include/dsn.h
alias.o: ../../include/dsn_buf.h
@@ -105,6 +106,7 @@ command.o: ../../include/been_here.h
command.o: ../../include/bounce.h
command.o: ../../include/defer.h
command.o: ../../include/deliver_request.h
+command.o: ../../include/delivered_hdr.h
command.o: ../../include/dict.h
command.o: ../../include/dsn.h
command.o: ../../include/dsn_buf.h
@@ -132,6 +134,7 @@ deliver_attr.o: ../../include/argv.h
deliver_attr.o: ../../include/attr.h
deliver_attr.o: ../../include/been_here.h
deliver_attr.o: ../../include/deliver_request.h
+deliver_attr.o: ../../include/delivered_hdr.h
deliver_attr.o: ../../include/dict.h
deliver_attr.o: ../../include/dsn.h
deliver_attr.o: ../../include/dsn_buf.h
@@ -149,40 +152,12 @@ deliver_attr.o: ../../include/vstream.h
deliver_attr.o: ../../include/vstring.h
deliver_attr.o: deliver_attr.c
deliver_attr.o: local.h
-delivered.o: ../../include/argv.h
-delivered.o: ../../include/attr.h
-delivered.o: ../../include/been_here.h
-delivered.o: ../../include/deliver_request.h
-delivered.o: ../../include/dict.h
-delivered.o: ../../include/dsn.h
-delivered.o: ../../include/dsn_buf.h
-delivered.o: ../../include/header_opts.h
-delivered.o: ../../include/htable.h
-delivered.o: ../../include/is_header.h
-delivered.o: ../../include/maps.h
-delivered.o: ../../include/mbox_conf.h
-delivered.o: ../../include/msg.h
-delivered.o: ../../include/msg_stats.h
-delivered.o: ../../include/quote_822_local.h
-delivered.o: ../../include/quote_flags.h
-delivered.o: ../../include/rec_type.h
-delivered.o: ../../include/recipient_list.h
-delivered.o: ../../include/record.h
-delivered.o: ../../include/resolve_clnt.h
-delivered.o: ../../include/stringops.h
-delivered.o: ../../include/sys_defs.h
-delivered.o: ../../include/tok822.h
-delivered.o: ../../include/vbuf.h
-delivered.o: ../../include/vstream.h
-delivered.o: ../../include/vstring.h
-delivered.o: ../../include/vstring_vstream.h
-delivered.o: delivered.c
-delivered.o: local.h
dotforward.o: ../../include/argv.h
dotforward.o: ../../include/attr.h
dotforward.o: ../../include/been_here.h
dotforward.o: ../../include/bounce.h
dotforward.o: ../../include/deliver_request.h
+dotforward.o: ../../include/delivered_hdr.h
dotforward.o: ../../include/dict.h
dotforward.o: ../../include/dsn.h
dotforward.o: ../../include/dsn_buf.h
@@ -221,6 +196,7 @@ file.o: ../../include/bounce.h
file.o: ../../include/defer.h
file.o: ../../include/deliver_flock.h
file.o: ../../include/deliver_request.h
+file.o: ../../include/delivered_hdr.h
file.o: ../../include/dict.h
file.o: ../../include/dsn.h
file.o: ../../include/dsn_buf.h
@@ -252,6 +228,7 @@ forward.o: ../../include/been_here.h
forward.o: ../../include/bounce.h
forward.o: ../../include/cleanup_user.h
forward.o: ../../include/deliver_request.h
+forward.o: ../../include/delivered_hdr.h
forward.o: ../../include/dict.h
forward.o: ../../include/dsn.h
forward.o: ../../include/dsn_buf.h
@@ -287,6 +264,7 @@ include.o: ../../include/been_here.h
include.o: ../../include/bounce.h
include.o: ../../include/defer.h
include.o: ../../include/deliver_request.h
+include.o: ../../include/delivered_hdr.h
include.o: ../../include/dict.h
include.o: ../../include/dsn.h
include.o: ../../include/dsn_buf.h
@@ -318,6 +296,7 @@ indirect.o: ../../include/been_here.h
indirect.o: ../../include/bounce.h
indirect.o: ../../include/defer.h
indirect.o: ../../include/deliver_request.h
+indirect.o: ../../include/delivered_hdr.h
indirect.o: ../../include/dict.h
indirect.o: ../../include/dsn.h
indirect.o: ../../include/dsn_buf.h
@@ -342,6 +321,7 @@ local.o: ../../include/attr.h
local.o: ../../include/been_here.h
local.o: ../../include/deliver_completed.h
local.o: ../../include/deliver_request.h
+local.o: ../../include/delivered_hdr.h
local.o: ../../include/dict.h
local.o: ../../include/dsn.h
local.o: ../../include/dsn_buf.h
@@ -374,6 +354,7 @@ local_expand.o: ../../include/argv.h
local_expand.o: ../../include/attr.h
local_expand.o: ../../include/been_here.h
local_expand.o: ../../include/deliver_request.h
+local_expand.o: ../../include/delivered_hdr.h
local_expand.o: ../../include/dict.h
local_expand.o: ../../include/dsn.h
local_expand.o: ../../include/dsn_buf.h
@@ -400,6 +381,7 @@ mailbox.o: ../../include/bounce.h
mailbox.o: ../../include/defer.h
mailbox.o: ../../include/deliver_pass.h
mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/delivered_hdr.h
mailbox.o: ../../include/dict.h
mailbox.o: ../../include/dsn.h
mailbox.o: ../../include/dsn_buf.h
@@ -436,6 +418,7 @@ maildir.o: ../../include/been_here.h
maildir.o: ../../include/bounce.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/delivered_hdr.h
maildir.o: ../../include/dict.h
maildir.o: ../../include/dsn.h
maildir.o: ../../include/dsn_buf.h
@@ -472,6 +455,7 @@ recipient.o: ../../include/bounce.h
recipient.o: ../../include/canon_addr.h
recipient.o: ../../include/defer.h
recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/delivered_hdr.h
recipient.o: ../../include/dict.h
recipient.o: ../../include/dsn.h
recipient.o: ../../include/dsn_buf.h
@@ -504,6 +488,7 @@ resolve.o: ../../include/been_here.h
resolve.o: ../../include/bounce.h
resolve.o: ../../include/defer.h
resolve.o: ../../include/deliver_request.h
+resolve.o: ../../include/delivered_hdr.h
resolve.o: ../../include/dict.h
resolve.o: ../../include/dsn.h
resolve.o: ../../include/dsn_buf.h
@@ -531,6 +516,7 @@ token.o: ../../include/been_here.h
token.o: ../../include/bounce.h
token.o: ../../include/defer.h
token.o: ../../include/deliver_request.h
+token.o: ../../include/delivered_hdr.h
token.o: ../../include/dict.h
token.o: ../../include/dsn.h
token.o: ../../include/dsn_buf.h
@@ -559,6 +545,7 @@ unknown.o: ../../include/been_here.h
unknown.o: ../../include/bounce.h
unknown.o: ../../include/deliver_pass.h
unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/delivered_hdr.h
unknown.o: ../../include/dict.h
unknown.o: ../../include/dsn.h
unknown.o: ../../include/dsn_buf.h
diff --git a/postfix/src/local/delivered.c b/postfix/src/local/delivered.c
deleted file mode 100644
index 20156ce5b..000000000
--- a/postfix/src/local/delivered.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*++
-/* NAME
-/* delivered 3
-/* SUMMARY
-/* process Delivered-To: headers
-/* SYNOPSIS
-/* #include "local.h"
-/*
-/* HTABLE *delivered_init(attr)
-/* DELIVER_ATTR attr;
-/*
-/* int delivered_find(table, address)
-/* HTABLE *table;
-/* const char *address;
-/*
-/* void delivered_free(table)
-/* HTABLE *table;
-/* DESCRIPTION
-/* This module processes addresses in Delivered-To: headers.
-/* These headers are added by some mail delivery systems, for the
-/* purpose of breaking mail forwarding loops. N.B. This solves
-/* a different problem than the Received: hop count limit. Hop
-/* counts are used to limit the impact of mail routing problems.
-/*
-/* delivered_init() extracts Delivered-To: header addresses
-/* from the specified message, and returns a table with the
-/* result.
-/*
-/* delivered_find() looks up the address in the lookup table,
-/* and returns non-zero when the address was found. The
-/* address argument must be in internalized form.
-/*
-/* delivered_free() releases storage that was allocated by
-/* delivered_init().
-/*
-/* Arguments:
-/* .IP state
-/* The attributes that specify the message, recipient and more.
-/* .IP table
-/* A table with extracted Delivered-To: addresses.
-/* .IP address
-/* A recipient address, internal form.
-/* DIAGNOSTICS
-/* Fatal errors: out of memory.
-/* SEE ALSO
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include
-#include
-#include
-#include
-
-/* Utility library. */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* Global library. */
-
-#include
-#include
-#include
-#include
-#include
-
-/* Application-specific. */
-
-#include "local.h"
-
-static VSTRING *buf;
-
-/* delivered_init - extract delivered-to information from the message */
-
-HTABLE *delivered_init(DELIVER_ATTR attr)
-{
- char *cp;
- HTABLE *table = htable_create(0);
- HEADER_OPTS *hdr;
-
- if (buf == 0)
- buf = vstring_alloc(10);
-
- if (vstream_fseek(attr.fp, attr.offset, SEEK_SET) < 0)
- msg_fatal("seek queue file %s: %m", VSTREAM_PATH(attr.fp));
-
- /*
- * XXX Assume that normal mail systems produce headers that fit in a
- * REC_TYPE_NORM record. Lowercase the delivered-to addresses for
- * consistency.
- */
- while (rec_get(attr.fp, buf, 0) == REC_TYPE_NORM) {
- if (is_header(STR(buf))) {
- if ((hdr = header_opts_find(STR(buf))) != 0
- && hdr->type == HDR_DELIVERED_TO) {
- cp = STR(buf) + strlen(hdr->name) + 1;
- while (ISSPACE(*cp))
- cp++;
- lowercase(cp);
- if (msg_verbose)
- msg_info("delivered_init: %s", cp);
- htable_enter(table, cp, (char *) 0);
- }
- } else if (ISSPACE(STR(buf)[0])) {
- continue;
- } else {
- break;
- }
- }
- return (table);
-}
-
-/* delivered_find - look up recipient in delivered table */
-
-int delivered_find(HTABLE *table, const char *address)
-{
- HTABLE_INFO *ht;
-
- /*
- * mail_copy() uses quote_822_local() when writing the Delivered-To:
- * header. We must therefore apply the same transformation when looking
- * up the recipient. Lowercase the delivered-to address for consistency.
- */
- quote_822_local(buf, address);
- lowercase(STR(buf));
- ht = htable_locate(table, STR(buf));
- return (ht != 0);
-}
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 557be6f4d..f46ed71b3 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -693,7 +693,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
state.msg_attr.request = rqst;
RESET_OWNER_ATTR(state.msg_attr, state.level);
RESET_USER_ATTR(usr_attr, state.level);
- state.loop_info = delivered_init(state.msg_attr); /* delivered-to */
+ state.loop_info = delivered_hdr_init(rqst->fp, rqst->data_offset);
state.request = rqst;
/*
@@ -717,7 +717,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
/*
* Clean up.
*/
- delivered_free(state.loop_info);
+ delivered_hdr_free(state.loop_info);
deliver_attr_free(&state.msg_attr);
return (msg_stat);
diff --git a/postfix/src/local/local.h b/postfix/src/local/local.h
index 67c3a9403..d63c99a65 100644
--- a/postfix/src/local/local.h
+++ b/postfix/src/local/local.h
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
/*
* User attributes: these control the privileges for delivery to external
@@ -107,7 +108,7 @@ typedef struct LOCAL_STATE {
int level; /* nesting level, for logging */
DELIVER_ATTR msg_attr; /* message attributes */
BH_TABLE *dup_filter; /* internal duplicate filter */
- HTABLE *loop_info; /* external loop filter */
+ DELIVERED_HDR_INFO *loop_info; /* external loop filter */
DELIVER_REQUEST *request; /* as from queue manager */
} LOCAL_STATE;
@@ -203,14 +204,6 @@ extern int local_mbox_lock_mask;
extern int local_deliver_hdr_mask;
- /*
- * delivered.c
- */
-extern HTABLE *delivered_init(DELIVER_ATTR);
-extern int delivered_find(HTABLE *, const char *);
-
-#define delivered_free(t) htable_free((t), (void (*) (char *)) 0)
-
/*
* forward.c
*/
diff --git a/postfix/src/local/recipient.c b/postfix/src/local/recipient.c
index e3bab10d0..e279eef0e 100644
--- a/postfix/src/local/recipient.c
+++ b/postfix/src/local/recipient.c
@@ -229,7 +229,7 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
* need for VERP specific bouncing code, at the cost of complicating the
* normal bounce sending procedure, but would simplify the code below.
*/
- if (delivered_find(state.loop_info, state.msg_attr.rcpt.address)) {
+ if (delivered_hdr_find(state.loop_info, state.msg_attr.rcpt.address)) {
VSTRING *canon_owner = 0;
if (var_ownreq_special) {
diff --git a/postfix/src/pipe/Makefile.in b/postfix/src/pipe/Makefile.in
index c661d7420..b9f534fbd 100644
--- a/postfix/src/pipe/Makefile.in
+++ b/postfix/src/pipe/Makefile.in
@@ -64,6 +64,7 @@ pipe.o: ../../include/canon_addr.h
pipe.o: ../../include/defer.h
pipe.o: ../../include/deliver_completed.h
pipe.o: ../../include/deliver_request.h
+pipe.o: ../../include/delivered_hdr.h
pipe.o: ../../include/dict.h
pipe.o: ../../include/dsn.h
pipe.o: ../../include/dsn_buf.h
diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c
index d56584ca7..ec163e15d 100644
--- a/postfix/src/pipe/pipe.c
+++ b/postfix/src/pipe/pipe.c
@@ -23,9 +23,11 @@
/* SINGLE-RECIPIENT DELIVERY
/* .ad
/* .fi
-/* Some external commands cannot handle more than one recipient
-/* per delivery request. Examples of such transports are pagers
-/* or fax machines.
+/* Some destinations cannot handle more than one recipient per
+/* delivery request. Examples are pagers or fax machines.
+/* In addition, multi-recipient delivery is undesirable when
+/* prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
+/* message header.
/*
/* To prevent Postfix from sending multiple recipients per delivery
/* request, specify
@@ -74,7 +76,13 @@
/* .IP \fBD\fR
/* Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
/* envelope recipient address. Note: for this to work, the
-/* \fItransport\fB_destination_recipient_limit\fR must be 1.
+/* \fItransport\fB_destination_recipient_limit\fR must be 1
+/* (see SINGLE-RECIPIENT DELIVERY above for details).
+/* .sp
+/* This code also enforces loop detection (Postfix 2.5 and later).
+/* If a message already contains a \fBDelivered-To:\fR header
+/* with the same recipient address, then the message is
+/* returned as undeliverable.
/* .sp
/* This feature is available as of Postfix 2.0.
/* .IP \fBF\fR
@@ -84,15 +92,18 @@
/* .IP \fBO\fR
/* Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
/* with the recipient address as given to Postfix. Note: for this to
-/* work, the \fItransport\fB_destination_recipient_limit\fR must be 1.
+/* work, the \fItransport\fB_destination_recipient_limit\fR must be 1
+/* (see SINGLE-RECIPIENT DELIVERY above for details).
/* .sp
/* This feature is available as of Postfix 2.0.
/* .IP \fBR\fR
/* Prepend a \fBReturn-Path:\fR message header with the envelope sender
/* address.
/* .IP \fBh\fR
-/* Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
-/* host name to lower case.
+/* Fold the command-line \fB$recipient\fR address domain part
+/* (text to the right of the right-most \fB@\fR character) to
+/* lower case; fold the entire command-line \fB$domain\fR and
+/* \fB$nexthop\fR host or domain information to lower case.
/* This is recommended for delivery via \fBUUCP\fR.
/* .IP \fBq\fR
/* Quote white space and other special characters in the command-line
@@ -149,7 +160,7 @@
/* command -f $sender -- $recipient (\fIgood\fR)
/* .fi
/* .IP
-/* This feature is available with Postfix 2.3 and later.
+/* This feature is available as of Postfix 2.3.
/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
/* Messages greater in size than this limit (in bytes) will
/* be returned to the sender as undeliverable.
@@ -191,6 +202,14 @@
/* This macro expands to the remote client protocol.
/* .sp
/* This is available in Postfix 2.2 and later.
+/* .IP \fB${\fBdomain\fR}\fR
+/* This macro expands to the domain portion of the recipient
+/* address. For example, with an address \fIuser+foo@domain\fR
+/* the domain is \fIdomain\fR.
+/* .sp
+/* This information is modified by the \fBh\fR flag for case folding.
+/* .sp
+/* This is available in Postfix 2.5 and later.
/* .IP \fB${\fBextension\fR}\fR
/* This macro expands to the extension part of a recipient address.
/* For example, with an address \fIuser+foo@domain\fR the extension is
@@ -420,6 +439,7 @@
#include
#include
#include
+#include
/* Single server skeleton. */
@@ -441,6 +461,7 @@
#define PIPE_DICT_USER "user" /* key */
#define PIPE_DICT_EXTENSION "extension" /* key */
#define PIPE_DICT_MAILBOX "mailbox" /* key */
+#define PIPE_DICT_DOMAIN "domain"/* key */
#define PIPE_DICT_SIZE "size" /* key */
#define PIPE_DICT_CLIENT_ADDR "client_address" /* key */
#define PIPE_DICT_CLIENT_NAME "client_hostname" /* key */
@@ -458,6 +479,7 @@
#define PIPE_FLAG_USER (1<<1)
#define PIPE_FLAG_EXTENSION (1<<2)
#define PIPE_FLAG_MAILBOX (1<<3)
+#define PIPE_FLAG_DOMAIN (1<<4)
/*
* Additional flags. These are colocated with mail_copy() flags. Allow some
@@ -531,6 +553,7 @@ static int parse_callback(int type, VSTRING *buf, char *context)
PIPE_DICT_USER, PIPE_FLAG_USER,
PIPE_DICT_EXTENSION, PIPE_FLAG_EXTENSION,
PIPE_DICT_MAILBOX, PIPE_FLAG_MAILBOX,
+ PIPE_DICT_DOMAIN, PIPE_FLAG_DOMAIN,
PIPE_DICT_SIZE, 0,
PIPE_DICT_CLIENT_ADDR, 0,
PIPE_DICT_CLIENT_NAME, 0,
@@ -609,6 +632,7 @@ static ARGV *expand_argv(const char *service, char **argv,
PIPE_STATE state;
int i;
char *ext;
+ char *dom;
/*
* This appears to be simple operation (replace $name by its expansion).
@@ -700,6 +724,22 @@ static ARGV *expand_argv(const char *service, char **argv,
dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
}
+ /*
+ * This argument contains $domain. Extract the domain name:
+ * anything to the right of the rightmost @.
+ */
+ if (state.expand_flag & PIPE_FLAG_DOMAIN) {
+ morph_recipient(buf, rcpt_list->info[i].address,
+ flags & PIPE_OPT_FOLD_FLAGS);
+ dom = split_at_right(STR(buf), '@');
+ if (dom == 0) {
+ msg_warn("no @ in recipient address: %s",
+ rcpt_list->info[i].address);
+ dom = ""; /* insert null arg */
+ }
+ dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
+ }
+
/*
* Done.
*/
@@ -1073,6 +1113,32 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
return (deliver_status);
}
+ /*
+ * Report mail delivery loops. By definition, this requires
+ * single-recipient delivery. Don't silently lose recipients.
+ */
+ if (attr.flags & MAIL_COPY_DELIVERED) {
+ DELIVERED_HDR_INFO *info;
+ RECIPIENT *rcpt;
+ int loop_found;
+
+ if (request->rcpt_list.len > 1)
+ msg_panic("%s: delivered-to enabled with multi-recipient request",
+ myname);
+ info = delivered_hdr_init(request->fp, request->data_offset);
+ rcpt = request->rcpt_list.info;
+ loop_found = delivered_hdr_find(info, rcpt->address);
+ delivered_hdr_free(info);
+ if (loop_found) {
+ dsb_simple(why, "5.4.6", "mail forwarding loop for %s",
+ rcpt->address);
+ deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
+ request, request->fp, why);
+ DELIVER_MSG_CLEANUP();
+ return (deliver_status);
+ }
+ }
+
/*
* Deliver. Set the nexthop and sender variables, and expand the command
* argument vector. Recipients will be expanded on the fly. XXX Rewrite
diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
index 601a1f538..70522679f 100644
--- a/postfix/src/smtpd/smtpd.c
+++ b/postfix/src/smtpd/smtpd.c
@@ -2131,6 +2131,10 @@ static void mail_reset(SMTPD_STATE *state)
myfree(state->saved_redirect);
state->saved_redirect = 0;
}
+ if (state->saved_bcc) {
+ myfree(state->saved_bcc);
+ state->saved_bcc = 0;
+ }
state->saved_flags = 0;
#ifdef DELAY_ACTION
state->saved_delay = 0;
@@ -2712,6 +2716,12 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (state->saved_redirect)
rec_fprintf(state->cleanup, REC_TYPE_RDR, "%s",
state->saved_redirect);
+ if (state->saved_bcc) {
+ rec_fprintf(state->cleanup, REC_TYPE_RCPT, "%s",
+ state->saved_bcc);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_DSN_NOTIFY, DSN_NOTIFY_NEVER);
+ }
if (state->saved_flags)
rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d",
state->saved_flags);
diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h
index 44478605c..d44978050 100644
--- a/postfix/src/smtpd/smtpd.h
+++ b/postfix/src/smtpd/smtpd.h
@@ -133,6 +133,7 @@ typedef struct SMTPD_STATE {
int discard; /* discard message */
char *saved_filter; /* postponed filter action */
char *saved_redirect; /* postponed redirect action */
+ char *saved_bcc; /* postponed bcc action */
int saved_flags; /* postponed hold/discard */
#ifdef DELAY_ACTION
int saved_delay; /* postponed deferred delay */
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index dde160828..6a3e14351 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -2099,6 +2099,32 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
}
}
+ /*
+ * BCC means deliver to designated recipient. But we may still
+ * change our mind, and reject/discard the message for other reasons.
+ */
+#ifdef SNAPSHOT
+ if (STREQUAL(value, "BCC", cmd_len)) {
+#ifndef TEST
+ if (can_delegate_action(state, table, "BCC", reply_class) == 0)
+ return (SMTPD_CHECK_DUNNO);
+#endif
+ if (strchr(cmd_text, '@') == 0) {
+ msg_warn("access table %s entry \"%s\" requires user@domain target",
+ table, datum);
+ return (SMTPD_CHECK_DUNNO);
+ } else {
+ vstring_sprintf(error_text, "<%s>: %s triggers BCC %s",
+ reply_name, reply_class, cmd_text);
+ log_whatsup(state, "bcc", STR(error_text));
+#ifndef TEST
+ UPDATE_STRING(state->saved_bcc, cmd_text);
+#endif
+ return (SMTPD_CHECK_DUNNO);
+ }
+ }
+#endif
+
/*
* DEFER_IF_PERMIT changes "permit" into "maybe". Use optional text or
* generate a generic error response.
diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c
index 1f8092dbf..a104a1174 100644
--- a/postfix/src/smtpd/smtpd_state.c
+++ b/postfix/src/smtpd/smtpd_state.c
@@ -123,6 +123,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream,
state->proxy_xforward_features = 0;
state->saved_filter = 0;
state->saved_redirect = 0;
+ state->saved_bcc = 0;
state->saved_flags = 0;
#ifdef DELAY_ACTION
state->saved_delay = 0;
diff --git a/postfix/src/trivial-rewrite/Makefile.in b/postfix/src/trivial-rewrite/Makefile.in
index 6b3ae51a3..6f4e24e8f 100644
--- a/postfix/src/trivial-rewrite/Makefile.in
+++ b/postfix/src/trivial-rewrite/Makefile.in
@@ -119,6 +119,7 @@ rewrite.o: trivial-rewrite.h
transport.o: ../../include/argv.h
transport.o: ../../include/attr.h
transport.o: ../../include/dict.h
+transport.o: ../../include/events.h
transport.o: ../../include/iostuff.h
transport.o: ../../include/mail_params.h
transport.o: ../../include/mail_proto.h
diff --git a/postfix/src/trivial-rewrite/transport.c b/postfix/src/trivial-rewrite/transport.c
index 890517746..7750a372b 100644
--- a/postfix/src/trivial-rewrite/transport.c
+++ b/postfix/src/trivial-rewrite/transport.c
@@ -69,6 +69,7 @@
#include
#include
#include
+#include
/* Global library. */
@@ -99,8 +100,10 @@ TRANSPORT_INFO *transport_pre_init(const char *transport_maps_name,
tp->transport_path = maps_create(transport_maps_name, transport_maps,
DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
| DICT_FLAG_NO_REGSUB);
- tp->wildcard_channel = tp->wildcard_nexthop = 0;
+ tp->wildcard_channel = vstring_alloc(10);
+ tp->wildcard_nexthop = vstring_alloc(10);
tp->transport_errno = 0;
+ tp->expire = 0;
return (tp);
}
@@ -204,8 +207,6 @@ static int find_transport_entry(TRANSPORT_INFO *tp, const char *key,
static void transport_wildcard_init(TRANSPORT_INFO *tp)
{
- VSTRING *channel = vstring_alloc(10);
- VSTRING *nexthop = vstring_alloc(10);
/*
* Technically, the wildcard lookup pattern is redundant. A static map
@@ -221,22 +222,20 @@ static void transport_wildcard_init(TRANSPORT_INFO *tp)
#define FULL 0
#define PARTIAL DICT_FLAG_FIXED
- if (find_transport_entry(tp, WILDCARD, "", FULL, channel, nexthop)) {
+ if (find_transport_entry(tp, WILDCARD, "", FULL,
+ tp->wildcard_channel,
+ tp->wildcard_nexthop)) {
tp->transport_errno = 0;
- if (tp->wildcard_channel)
- vstring_free(tp->wildcard_channel);
- tp->wildcard_channel = channel;
- if (tp->wildcard_nexthop)
- vstring_free(tp->wildcard_nexthop);
- tp->wildcard_nexthop = nexthop;
if (msg_verbose)
msg_info("wildcard_{chan:hop}={%s:%s}",
- vstring_str(channel), vstring_str(nexthop));
+ vstring_str(tp->wildcard_channel),
+ vstring_str(tp->wildcard_nexthop));
} else {
tp->transport_errno = dict_errno;
- vstring_free(channel);
- vstring_free(nexthop);
+ VSTRING_RESET(tp->wildcard_channel);
+ VSTRING_RESET(tp->wildcard_nexthop);
}
+ tp->expire = event_time() + 30; /* XXX make configurable */
}
/* transport_lookup - map a transport domain */
@@ -321,12 +320,12 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr,
/*
* Fall back to the wild-card entry.
*/
- if (tp->transport_errno)
+ if (tp->transport_errno || event_time() > tp->expire)
transport_wildcard_init(tp);
if (tp->transport_errno) {
dict_errno = tp->transport_errno;
return (NOTFOUND);
- } else if (tp->wildcard_channel) {
+ } else if (tp->wildcard_channel && VSTRING_LEN(tp->wildcard_channel)) {
update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop),
rcpt_domain, channel, nexthop);
return (FOUND);
diff --git a/postfix/src/trivial-rewrite/transport.h b/postfix/src/trivial-rewrite/transport.h
index 27912d821..0660f97b5 100644
--- a/postfix/src/trivial-rewrite/transport.h
+++ b/postfix/src/trivial-rewrite/transport.h
@@ -8,6 +8,11 @@
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include
+
/*
* Utility library.
*/
@@ -26,6 +31,7 @@ typedef struct TRANSPORT_INFO {
VSTRING *wildcard_channel;
VSTRING *wildcard_nexthop;
int transport_errno;
+ time_t expire;
} TRANSPORT_INFO;
extern TRANSPORT_INFO *transport_pre_init(const char *, const char *);