mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
snapshot-20010709
This commit is contained in:
committed by
Viktor Dukhovni
parent
7e8044da83
commit
a94bf41134
1
postfix/.indent.pro
vendored
1
postfix/.indent.pro
vendored
@@ -1,3 +1,4 @@
|
||||
-TABOUNCE
|
||||
-TALIAS_TOKEN
|
||||
-TARGV
|
||||
-TBH_TABLE
|
||||
|
@@ -25,7 +25,7 @@ lmtp support yes (client)
|
||||
m4 config no
|
||||
mail to command yes (configurable for .forward, aliases, :include:)
|
||||
mail to file yes (configurable for .forward, aliases, :include:)
|
||||
maildir yes (with procmail)
|
||||
maildir yes
|
||||
mailertable yes (it's called transport)
|
||||
mailq yes
|
||||
majordomo yes (edit approve script to delete /delivered-to/i)
|
||||
@@ -38,6 +38,7 @@ nis tables yes
|
||||
nis+ tables not yet
|
||||
pipeline option yes (server and client)
|
||||
pop/imap yes (with third-party daemons that use /var[/spool]/mail)
|
||||
qmqp server yes (with verp support)
|
||||
rbl support yes
|
||||
return-receipt: not yet
|
||||
sasl support yes (compile time option)
|
||||
@@ -55,5 +56,6 @@ user+extension yes (also: .forward+extension)
|
||||
user-extension yes (also: .forward-extension)
|
||||
user.lock yes (runtime configurable)
|
||||
uucp support yes (sends user@domain recipients)
|
||||
verp support yes (delimiters are configurable)
|
||||
virtual domains yes
|
||||
year 2000 safe yes
|
||||
|
@@ -5292,13 +5292,12 @@ Apologies for any names omitted.
|
||||
|
||||
Cleanup: the virtual delivery agent was poorly integrated
|
||||
so that the SMTP server and queue manager did not reject
|
||||
mail for unknown users. Files: smtpd/smtpd_check.c,
|
||||
*qmgr/qmgr_message.c.
|
||||
mail for unknown users. Files: smtpd/smtpd_check.c.
|
||||
|
||||
20010705
|
||||
|
||||
Feature: QMQP server for compatibility with the ezmlm list
|
||||
manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c.
|
||||
Feature: QMQP server, compatible with qmail and the ezmlm
|
||||
list manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c.
|
||||
|
||||
20010706
|
||||
|
||||
@@ -5309,3 +5308,17 @@ Apologies for any names omitted.
|
||||
|
||||
Bugfix: with disable_dns=yes, the SMTP client treated all
|
||||
host lookup errors as permanent. File: smtp/smtp_addr.c.
|
||||
|
||||
20010709
|
||||
|
||||
Feature: VERP support, based on a patch by Peng Yong, and
|
||||
with the missing parts filled in so that the Postfix bounce
|
||||
daemon can send one VERP bounce per undeliverable recipient.
|
||||
Files: , sendmail/sendmail.c, smtpd/smtpd.c, qmgr/qmgr_deliver.c,
|
||||
bounce/bounce_notify_verp.c, qmqpd/qmqpd.c, plus a couple
|
||||
support routines in the global library.
|
||||
|
||||
Cleanup: with recipient_delimiter=+ (or any character other
|
||||
than -) Postfix will now recognize address extensions even
|
||||
with owner-foo+extension addresses. This is necessary to
|
||||
make VERP work for mailing lists.
|
||||
|
@@ -145,7 +145,7 @@ expect to run more than 1000 delivery processes, you may need to
|
||||
override the definition of the FD_SETSIZE macro to make select()
|
||||
work correctly:
|
||||
|
||||
% make makefiles CCARGS=-FD_SETSIZE=2048
|
||||
% make makefiles CCARGS=-DFD_SETSIZE=2048
|
||||
|
||||
In any case, if the command
|
||||
|
||||
|
@@ -6,8 +6,8 @@ that Postfix can be used as a backend for the Ezmlm-idx mailing
|
||||
list manager. This support includes qmqp-source and qmqp-sink
|
||||
programs for protocol stress testing.
|
||||
|
||||
Turning on the QMQP service
|
||||
===========================
|
||||
Turning on the Postfix QMQP service
|
||||
===================================
|
||||
|
||||
To enable QMQP server support on an existing Postfix system you
|
||||
have to add the following line to /etc/postfix/master.cf:
|
||||
@@ -15,8 +15,8 @@ have to add the following line to /etc/postfix/master.cf:
|
||||
628 inet n - n - - qmqpd
|
||||
|
||||
|
||||
QMQP server access control
|
||||
==========================
|
||||
Postfix QMQP server access control
|
||||
==================================
|
||||
|
||||
By default, the QMQP server does not accept mail from any client.
|
||||
This is because the QMQP server relays mail to any destination
|
||||
@@ -37,3 +37,9 @@ instead.
|
||||
Patterns are separated by whitespace and/or commas. In order to
|
||||
reverse the result, precede a non-file name pattern with an
|
||||
exclamation point (!).
|
||||
|
||||
Setting up Ezmlm-idx to use Postfix QMQP support
|
||||
================================================
|
||||
|
||||
You need to list the Postfix IP address in a suitable configuration
|
||||
file. See the ezmlm-idx documentation for details.
|
@@ -1,17 +1,33 @@
|
||||
Incompatible changes with snapshot-20010707
|
||||
Incompatible changes with snapshot-20010709
|
||||
===========================================
|
||||
|
||||
The SMTP client by default breaks lines > 2048 characters, in order
|
||||
to avoid problems with mail delivery to fragile SMTP server software.
|
||||
To get the old behavior, specify "smtp_break_lines = no" in the
|
||||
Postfix main.cf file.
|
||||
This release introduces a new queue file record type that is used
|
||||
only for messages that actually use VERP (variable envelope return
|
||||
path) support. With this sole exception, the queue file format is
|
||||
entirely backwards compatible with previous Postfix releases.
|
||||
|
||||
Major changes with snapshot-20010707
|
||||
The SMTP client now by default breaks lines > 2048 characters, to
|
||||
avoid mail delivery problems with fragile SMTP server software.
|
||||
To get the old behavior back, specify "smtp_break_lines = no" in
|
||||
the Postfix main.cf file.
|
||||
|
||||
With recipient_delimiter=+ (or any character other than -) Postfix
|
||||
will now recognize address extensions even with owner-foo+extension
|
||||
addresses. This change was necessary to make VERP useful for mailing
|
||||
list bounce processing.
|
||||
|
||||
Major changes with snapshot-20010709
|
||||
====================================
|
||||
|
||||
QMQP server support, so that Postfix can be used as a backend mailer
|
||||
for the Ezmlm-idx mailing list manager. The service is disabled by
|
||||
default. To enable, follow instructions in the README_QMQP file.
|
||||
for the ezmlm-idx mailing list manager. You still need qmail to
|
||||
drive ezmlm and to process mailing list bounces. The QMQP service
|
||||
is disabled by default. To enable, follow the instructions in the
|
||||
QMQP_README file.
|
||||
|
||||
VERP (variable envelope return path) support. This is enabled by
|
||||
default. See the VERP_README file for instructions. These instructions
|
||||
need more examples for how to process bounces automatically.
|
||||
|
||||
You can now reject unknown virtual(8) recipients at the SMTP port
|
||||
by specifying a "domain.name whatever" entry in the tables specified
|
||||
|
96
postfix/VERP_README
Normal file
96
postfix/VERP_README
Normal file
@@ -0,0 +1,96 @@
|
||||
Postfix VERP support
|
||||
====================
|
||||
|
||||
Postfix supports variable envelope return path addresses, which
|
||||
means that each recipient receives a customized copy of the message,
|
||||
with the recipient address encoded in the envelope sender address.
|
||||
This concept was popularized by the qmail MTA and by the ezmlm
|
||||
mailing list manager.
|
||||
|
||||
When VERP style delivery is requested, Postfix delivers mail with
|
||||
sender address prefix@origin for a recipient user@domain, with a
|
||||
sender address that encodes the recipient as follows:
|
||||
|
||||
prefix+user=domain@origin
|
||||
|
||||
so that undeliverable mail reveals what address was undeliverable.
|
||||
|
||||
The + and = are the default VERP delimiters. You can specify non-
|
||||
default delimiters in main.cf with the default_verp_delimiters
|
||||
configuration parameter (default value: +=). Specify two characters;
|
||||
the first delimiter should match the $recipient_delimiter setting.
|
||||
|
||||
Using VERP with majordomo etc. mailing lists
|
||||
============================================
|
||||
|
||||
In order to make VERP useful with majordomo etc. mailing lists,
|
||||
you would configure the list manager to submit mail as:
|
||||
|
||||
sendmail -V -f owner-listname other-arguments...
|
||||
|
||||
This text assumes that you have set up an owner-listname alias that
|
||||
routes undeliverable mail to a real person:
|
||||
|
||||
/etc/aliases:
|
||||
owner-listname: yourname+listname
|
||||
|
||||
In order to process bounces we are going to make extensive use of
|
||||
address extension tricks.
|
||||
|
||||
You need to tell Postfix that + is the separator between an address
|
||||
and its optional address extension, that address extensions are
|
||||
appended to .forward file names, and that address extensions are
|
||||
to be discarded when doing alias expansions:
|
||||
|
||||
/etc/postfix/main.cf:
|
||||
recipient_delimiter = +
|
||||
forward_path = $home/.forward${recipient_delimiter}${extension},$home/.forward
|
||||
propagate_unmatched_extensions = canonical, virtual
|
||||
|
||||
(the last two parameter settings are default settings).
|
||||
|
||||
You need to set up a file named .forward+listname with the commands
|
||||
that process all the mail that is sent to the owner-listname address:
|
||||
|
||||
~/.forward+listname:
|
||||
"|/some/where/command ..."
|
||||
|
||||
With this set up, undeliverable mail for user@domain will be returned
|
||||
to the following address:
|
||||
|
||||
owner-listname+user=domain@your.domain
|
||||
|
||||
which is processed by the command in your .forward+listname file.
|
||||
|
||||
It is left as an exercise for the reader to parse the To: header
|
||||
line and to pull out the user=domain part from the recipient address.
|
||||
|
||||
VERP support in the Postfix SMTP server
|
||||
=======================================
|
||||
|
||||
The Postfix SMTP server has a new command XVERP to enable VERP
|
||||
style delivery. The syntax allows two forms:
|
||||
|
||||
MAIL FROM:<sender@domain> XVERP
|
||||
MAIL FROM:<sender@domain> XVERP=xy
|
||||
|
||||
where x and y are the VERP delimiters. When no VERP delimiters
|
||||
are specified, Postfix uses the two characters specified with the
|
||||
default_verp_delimiters configuration parameter.
|
||||
|
||||
VERP support in the Postfix sendmail command
|
||||
============================================
|
||||
|
||||
The Postfix sendmail command has a -V flag to request VERP style
|
||||
delivery. It is not possible to override the default VERP delimiters.
|
||||
|
||||
VERP support in the Postfix QMQP server
|
||||
=======================================
|
||||
|
||||
When the Postfix QMQP server receives mail with a an envelope sender
|
||||
address of the form:
|
||||
|
||||
prefix-@origin-@[]
|
||||
|
||||
Postfix generates VERP sender addresses using prefix@domain as the
|
||||
original sender address, and using "-=" as the VERP delimiters.
|
@@ -94,33 +94,38 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
<b>-U</b> (ignored)
|
||||
Initial user submission.
|
||||
|
||||
<b>-bd</b> Go into daemon mode. This mode of operation is
|
||||
<b>-V</b> Variable Envelope Return Path. Given an envelope
|
||||
sender address <i>prefix</i>-@<i>origin</i>, each recipient
|
||||
<i>user@domain</i> receives mail with a personalized enve-
|
||||
lope sender address <i>prefix</i><b>-</b><i>user=domain</i>@<i>origin</i>.
|
||||
|
||||
<b>-bd</b> Go into daemon mode. This mode of operation is
|
||||
implemented by executing the <b>postfix</b> <b>start</b> command.
|
||||
|
||||
<b>-bi</b> Initialize alias database. See the <b>newaliases</b> com-
|
||||
<b>-bi</b> Initialize alias database. See the <b>newaliases</b> com-
|
||||
mand above.
|
||||
|
||||
<b>-bm</b> Read mail from standard input and arrange for
|
||||
<b>-bm</b> Read mail from standard input and arrange for
|
||||
delivery. This is the default mode of operation.
|
||||
|
||||
<b>-bp</b> List the mail queue. See the <b>mailq</b> command above.
|
||||
|
||||
<b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands
|
||||
from standard input, and write responses to stan-
|
||||
<b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands
|
||||
from standard input, and write responses to stan-
|
||||
dard output. This mode of operation is implemented
|
||||
by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon.
|
||||
|
||||
<b>-f</b> <i>sender</i>
|
||||
Set the envelope sender address. This is the
|
||||
address where delivery problems are sent to, unless
|
||||
the message contains an <b>Errors-To:</b> message header.
|
||||
the message contains an <b>Errors-To:</b> message header.
|
||||
|
||||
<b>-h</b> <i>hop_count</i> (ignored)
|
||||
Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
|
||||
Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
|
||||
tion parameter instead.
|
||||
|
||||
<b>-i</b> When reading a message from standard input, don't
|
||||
treat a line with only a <b>.</b> character as the end of
|
||||
<b>-i</b> When reading a message from standard input, don't
|
||||
treat a line with only a <b>.</b> character as the end of
|
||||
input.
|
||||
|
||||
<b>-m</b> (ignored)
|
||||
@@ -130,68 +135,68 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
Backwards compatibility.
|
||||
|
||||
<b>-oA</b><i>alias_database</i>
|
||||
Non-default alias database. Specify <i>pathname</i> or
|
||||
Non-default alias database. Specify <i>pathname</i> or
|
||||
<i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
|
||||
|
||||
<b>-o7</b> (ignored)
|
||||
|
||||
<b>-o8</b> (ignored)
|
||||
The message body type. Currently, Postfix imple-
|
||||
The message body type. Currently, Postfix imple-
|
||||
ments <b>just-send-eight</b>.
|
||||
|
||||
<b>-oi</b> When reading a message from standard input, don't
|
||||
treat a line with only a <b>.</b> character as the end of
|
||||
<b>-oi</b> When reading a message from standard input, don't
|
||||
treat a line with only a <b>.</b> character as the end of
|
||||
input.
|
||||
|
||||
<b>-om</b> (ignored)
|
||||
The sender is never eliminated from alias etc.
|
||||
The sender is never eliminated from alias etc.
|
||||
expansions.
|
||||
|
||||
<b>-o</b> <i>x</i> <i>value</i> (ignored)
|
||||
Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
|
||||
Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
|
||||
ration parameter in <b>main.cf</b> instead.
|
||||
|
||||
<b>-r</b> <i>sender</i>
|
||||
Set the envelope sender address. This is the
|
||||
address where delivery problems are sent to, unless
|
||||
the message contains an <b>Errors-To:</b> message header.
|
||||
the message contains an <b>Errors-To:</b> message header.
|
||||
|
||||
<b>-q</b> Attempt to deliver all queued mail. This is imple-
|
||||
<b>-q</b> Attempt to deliver all queued mail. This is imple-
|
||||
mented by kicking the <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon.
|
||||
|
||||
<b>-q</b><i>interval</i> (ignored)
|
||||
The interval between queue runs. Use the
|
||||
The interval between queue runs. Use the
|
||||
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
|
||||
|
||||
<b>-qR</b><i>site</i>
|
||||
Schedule immediate delivery of all mail that is
|
||||
queued for the named <i>site</i>. Depending on the desti-
|
||||
nation, this uses "fast flush" service, or it has
|
||||
the same effect as <b>sendmail</b> <b>-q</b>. This is imple-
|
||||
Schedule immediate delivery of all mail that is
|
||||
queued for the named <i>site</i>. Depending on the desti-
|
||||
nation, this uses "fast flush" service, or it has
|
||||
the same effect as <b>sendmail</b> <b>-q</b>. This is imple-
|
||||
mented by connecting to the local SMTP server. See
|
||||
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> for more information about the "fast
|
||||
flush" service.
|
||||
|
||||
<b>-qS</b><i>site</i>
|
||||
This command is not implemented. Use the slower
|
||||
This command is not implemented. Use the slower
|
||||
<b>sendmail</b> <b>-q</b> command instead.
|
||||
|
||||
<b>-t</b> Extract recipients from message headers. This
|
||||
requires that no recipients be specified on the
|
||||
<b>-t</b> Extract recipients from message headers. This
|
||||
requires that no recipients be specified on the
|
||||
command line.
|
||||
|
||||
<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>SECURITY</b>
|
||||
By design, this program is not set-user (or group) id.
|
||||
However, it must handle data from untrusted users or
|
||||
untrusted machines. Thus, the usual precautions need to
|
||||
By design, this program is not set-user (or group) id.
|
||||
However, it must handle data from untrusted users or
|
||||
untrusted machines. Thus, the usual precautions need to
|
||||
be taken against malicious inputs.
|
||||
|
||||
<b>DIAGNOSTICS</b>
|
||||
Problems are logged to <b>syslogd</b>(8) and to the standard
|
||||
Problems are logged to <b>syslogd</b>(8) and to the standard
|
||||
error stream.
|
||||
|
||||
<b>ENVIRONMENT</b>
|
||||
@@ -203,7 +208,7 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
|
||||
<b>MAIL</b><i>_</i><b>DEBUG</b>
|
||||
Enable debugging with an external command, as spec-
|
||||
ified with the <b>debugger</b><i>_</i><b>command</b> configuration
|
||||
ified with the <b>debugger</b><i>_</i><b>command</b> configuration
|
||||
parameter.
|
||||
|
||||
<b>FILES</b>
|
||||
@@ -211,13 +216,13 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
/etc/postfix, configuration files
|
||||
|
||||
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
||||
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
|
||||
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>alias</b><i>_</i><b>database</b>
|
||||
Default alias database(s) for <b>newaliases</b>. The
|
||||
default value for this parameter is system-spe-
|
||||
Default alias database(s) for <b>newaliases</b>. The
|
||||
default value for this parameter is system-spe-
|
||||
cific.
|
||||
|
||||
<b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
|
||||
@@ -233,55 +238,55 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
initialized.
|
||||
|
||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
|
||||
Increment in verbose logging level when a remote
|
||||
Increment in verbose logging level when a remote
|
||||
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
|
||||
parameter.
|
||||
|
||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
|
||||
List of domain or network patterns. When a remote
|
||||
host matches a pattern, increase the verbose log-
|
||||
ging level by the amount specified in the
|
||||
List of domain or network patterns. When a remote
|
||||
host matches a pattern, increase the verbose log-
|
||||
ging level by the amount specified in the
|
||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
|
||||
|
||||
<b>fast</b><i>_</i><b>flush</b><i>_</i><b>domains</b>
|
||||
List of domains that will receive "fast flush" ser-
|
||||
vice (default: all domains that this system is
|
||||
willing to relay mail to). This greatly improves
|
||||
the performance of the SMTP <b>ETRN</b> request, and of
|
||||
the <b>sendmail</b> <b>-qR</b> command. For domains not in the
|
||||
vice (default: all domains that this system is
|
||||
willing to relay mail to). This greatly improves
|
||||
the performance of the SMTP <b>ETRN</b> request, and of
|
||||
the <b>sendmail</b> <b>-qR</b> command. For domains not in the
|
||||
list, Postfix simply attempts to deliver all queued
|
||||
mail.
|
||||
|
||||
<b>fork</b><i>_</i><b>attempts</b>
|
||||
Number of attempts to <b>fork</b>() a process before giv-
|
||||
Number of attempts to <b>fork</b>() a process before giv-
|
||||
ing up.
|
||||
|
||||
<b>fork</b><i>_</i><b>delay</b>
|
||||
Delay in seconds between successive <b>fork</b>()
|
||||
Delay in seconds between successive <b>fork</b>()
|
||||
attempts.
|
||||
|
||||
<b>hopcount</b><i>_</i><b>limit</b>
|
||||
Limit the number of <b>Received:</b> message headers.
|
||||
|
||||
<b>mail</b><i>_</i><b>owner</b>
|
||||
The owner of the mail queue and of most Postfix
|
||||
The owner of the mail queue and of most Postfix
|
||||
processes.
|
||||
|
||||
<b>command</b><i>_</i><b>directory</b>
|
||||
Directory with Postfix support commands (default:
|
||||
Directory with Postfix support commands (default:
|
||||
<b>$program</b><i>_</i><b>directory</b>).
|
||||
|
||||
<b>daemon</b><i>_</i><b>directory</b>
|
||||
Directory with Postfix daemon programs (default:
|
||||
Directory with Postfix daemon programs (default:
|
||||
<b>$program</b><i>_</i><b>directory</b>).
|
||||
|
||||
<b>queue</b><i>_</i><b>directory</b>
|
||||
Top-level directory of the Postfix queue. This is
|
||||
Top-level directory of the Postfix queue. This is
|
||||
also the root directory of Postfix daemons that run
|
||||
chrooted.
|
||||
|
||||
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
|
||||
The time between successive scans of the deferred
|
||||
The time between successive scans of the deferred
|
||||
queue.
|
||||
|
||||
<b>SEE</b> <b>ALSO</b>
|
||||
@@ -297,7 +302,7 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
syslogd(8) system logging
|
||||
|
||||
<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>
|
||||
|
@@ -35,8 +35,8 @@ SMTPD(8) SMTPD(8)
|
||||
<b>STANDARDS</b>
|
||||
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a> (Host requirements)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1869.html">RFC 1869</a> (SMTP service extensions)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1854.html">RFC 1854</a> (SMTP Pipelining)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
|
||||
<a href="http://www.faqs.org/rfcs/rfc1985.html">RFC 1985</a> (ETRN command)
|
||||
|
@@ -82,6 +82,11 @@ Log mailer traffic. Use the \fBdebug_peer_list\fR and
|
||||
\fBdebug_peer_level\fR configuration parameters instead.
|
||||
.IP "\fB-U\fR (ignored)"
|
||||
Initial user submission.
|
||||
.IP \fB-V\fR
|
||||
Variable Envelope Return Path. Given an envelope sender address
|
||||
\fIprefix\fR-@\fIorigin\fR, each recipient \fIuser@domain\fR
|
||||
receives mail with a personalized envelope sender address
|
||||
\fIprefix\fB-\fIuser=domain\fR@\fIorigin\fR.
|
||||
.IP \fB-bd\fR
|
||||
Go into daemon mode. This mode of operation is implemented by
|
||||
executing the \fBpostfix start\fR command.
|
||||
|
@@ -42,8 +42,8 @@ run chrooted at fixed low privilege.
|
||||
.nf
|
||||
RFC 821 (SMTP protocol)
|
||||
RFC 1123 (Host requirements)
|
||||
RFC 1651 (SMTP service extensions)
|
||||
RFC 1652 (8bit-MIME transport)
|
||||
RFC 1869 (SMTP service extensions)
|
||||
RFC 1854 (SMTP Pipelining)
|
||||
RFC 1870 (Message Size Declaration)
|
||||
RFC 1985 (ETRN command)
|
||||
|
@@ -1,8 +1,8 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \
|
||||
bounce_cleanup.c bounce_notify_util.c
|
||||
bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c
|
||||
OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \
|
||||
bounce_cleanup.o bounce_notify_util.o
|
||||
bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o
|
||||
HDRS =
|
||||
TESTSRC =
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
@@ -69,6 +69,7 @@ bounce.o: ../../include/mail_queue.h
|
||||
bounce.o: ../../include/mail_params.h
|
||||
bounce.o: ../../include/mail_conf.h
|
||||
bounce.o: ../../include/bounce.h
|
||||
bounce.o: ../../include/mail_addr.h
|
||||
bounce.o: ../../include/mail_server.h
|
||||
bounce.o: bounce_service.h
|
||||
bounce.o: ../../include/bounce_log.h
|
||||
@@ -133,3 +134,18 @@ bounce_notify_util.o: ../../include/name_mask.h
|
||||
bounce_notify_util.o: ../../include/bounce_log.h
|
||||
bounce_notify_util.o: ../../include/mail_date.h
|
||||
bounce_notify_util.o: bounce_service.h
|
||||
bounce_notify_verp.o: bounce_notify_verp.c
|
||||
bounce_notify_verp.o: ../../include/sys_defs.h
|
||||
bounce_notify_verp.o: ../../include/msg.h
|
||||
bounce_notify_verp.o: ../../include/vstream.h
|
||||
bounce_notify_verp.o: ../../include/vbuf.h
|
||||
bounce_notify_verp.o: ../../include/name_mask.h
|
||||
bounce_notify_verp.o: ../../include/mail_params.h
|
||||
bounce_notify_verp.o: ../../include/mail_queue.h
|
||||
bounce_notify_verp.o: ../../include/vstring.h
|
||||
bounce_notify_verp.o: ../../include/post_mail.h
|
||||
bounce_notify_verp.o: ../../include/cleanup_user.h
|
||||
bounce_notify_verp.o: ../../include/mail_addr.h
|
||||
bounce_notify_verp.o: ../../include/mail_error.h
|
||||
bounce_notify_verp.o: bounce_service.h
|
||||
bounce_notify_verp.o: ../../include/bounce_log.h
|
||||
|
@@ -80,6 +80,11 @@
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
@@ -95,6 +100,7 @@
|
||||
#include <mail_params.h>
|
||||
#include <mail_conf.h>
|
||||
#include <bounce.h>
|
||||
#include <mail_addr.h>
|
||||
|
||||
/* Single-threaded server skeleton. */
|
||||
|
||||
@@ -122,6 +128,7 @@ static VSTRING *queue_id;
|
||||
static VSTRING *queue_name;
|
||||
static VSTRING *recipient;
|
||||
static VSTRING *sender;
|
||||
static VSTRING *verp_delims;
|
||||
static VSTRING *why;
|
||||
|
||||
#define STR vstring_str
|
||||
@@ -199,7 +206,62 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
|
||||
* Execute the request.
|
||||
*/
|
||||
return (bounce_notify_service(service_name, STR(queue_name),
|
||||
STR(queue_id), STR(sender), flush));
|
||||
STR(queue_id), STR(sender), flush));
|
||||
}
|
||||
|
||||
/* bounce_verp_proto - bounce_notify server protocol, VERP style */
|
||||
|
||||
static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
|
||||
{
|
||||
char *myname="bounce_verp_proto";
|
||||
int flags;
|
||||
|
||||
/*
|
||||
* Read and validate the client request.
|
||||
*/
|
||||
if (mail_command_read(client, "%d %s %s %s %s",
|
||||
&flags, queue_name, queue_id,
|
||||
sender, verp_delims) != 5) {
|
||||
msg_warn("malformed request");
|
||||
return (-1);
|
||||
}
|
||||
if (mail_queue_name_ok(STR(queue_name)) == 0) {
|
||||
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
|
||||
return (-1);
|
||||
}
|
||||
if (mail_queue_id_ok(STR(queue_id)) == 0) {
|
||||
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
|
||||
return (-1);
|
||||
}
|
||||
if (strlen(STR(verp_delims)) != 2) {
|
||||
msg_warn("malformed verp delimiter string: %s",
|
||||
printable(STR(verp_delims), '?'));
|
||||
return (-1);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: service=%s queue=%s id=%s sender=%s delim=%s",
|
||||
myname, service_name, STR(queue_name), STR(queue_id),
|
||||
STR(sender), STR(verp_delims));
|
||||
|
||||
/*
|
||||
* On request by the client, set up a trap to delete the log file in case
|
||||
* of errors.
|
||||
*/
|
||||
if (flags & BOUNCE_FLAG_CLEAN)
|
||||
bounce_cleanup_register(service_name, STR(queue_id));
|
||||
|
||||
/*
|
||||
* Execute the request. Fall back to traditional notification if a bounce
|
||||
* was returned as undeliverable, because we don't want to VERPify those.
|
||||
*/
|
||||
if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
|
||||
msg_warn("request to send VERP-style notification of bounced mail");
|
||||
return (bounce_notify_service(service_name, STR(queue_name),
|
||||
STR(queue_id), STR(sender), flush));
|
||||
} else
|
||||
return (bounce_notify_verp(service_name, STR(queue_name),
|
||||
STR(queue_id), STR(sender),
|
||||
STR(verp_delims), flush));
|
||||
}
|
||||
|
||||
/* bounce_service - parse bounce command type and delegate */
|
||||
@@ -228,6 +290,8 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
|
||||
if (mail_scan(client, "%d", &command) != 1) {
|
||||
msg_warn("malformed request");
|
||||
status = -1;
|
||||
} else if (command == BOUNCE_CMD_VERP) {
|
||||
status = bounce_verp_proto(service_name, client, REALLY_BOUNCE);
|
||||
} else if (command == BOUNCE_CMD_FLUSH) {
|
||||
status = bounce_notify_proto(service_name, client, REALLY_BOUNCE);
|
||||
} else if (command == BOUNCE_CMD_WARN) {
|
||||
@@ -271,6 +335,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
|
||||
queue_name = vstring_alloc(10);
|
||||
recipient = vstring_alloc(10);
|
||||
sender = vstring_alloc(10);
|
||||
verp_delims = vstring_alloc(10);
|
||||
why = vstring_alloc(10);
|
||||
}
|
||||
|
||||
|
@@ -199,7 +199,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name,
|
||||
*/
|
||||
if ((bounce_info->log_handle = bounce_log_open(bounce_info->service,
|
||||
bounce_info->queue_id,
|
||||
O_RDONLY, 0)) == 0
|
||||
O_RDWR, 0)) == 0
|
||||
&& errno != ENOENT)
|
||||
msg_fatal("open %s %s: %m", bounce_info->service,
|
||||
bounce_info->queue_id);
|
||||
|
210
postfix/src/bounce/bounce_notify_verp.c
Normal file
210
postfix/src/bounce/bounce_notify_verp.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* bounce_notify_verp 3
|
||||
/* SUMMARY
|
||||
/* send non-delivery report to sender, server side
|
||||
/* SYNOPSIS
|
||||
/* #include "bounce_service.h"
|
||||
/*
|
||||
/* int bounce_notify_verp(service, queue_name, queue_id, sender,
|
||||
/* verp_delims, flush)
|
||||
/* char *queue_name;
|
||||
/* char *queue_id;
|
||||
/* char *sender;
|
||||
/* char *verp_delims;
|
||||
/* int flush;
|
||||
/* DESCRIPTION
|
||||
/* This module implements the server side of the bounce_notify()
|
||||
/* (send bounce message) request. If flush is zero, the logfile
|
||||
/* is not removed, and a warning is sent instead of a bounce.
|
||||
/* The bounce recipient address is encoded in VERP format.
|
||||
/* This routine must be used for single bounces only.
|
||||
/*
|
||||
/* When a message bounces, a full copy is sent to the originator,
|
||||
/* and an optional copy of the diagnostics with message headers is
|
||||
/* sent to the postmaster. The result is non-zero when the operation
|
||||
/* should be tried again.
|
||||
/*
|
||||
/* When a bounce is sent, the sender address is the empty
|
||||
/* address.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal error: error opening existing file. Warnings: corrupt
|
||||
/* message file. A corrupt message is saved to the "corrupt"
|
||||
/* queue for further inspection.
|
||||
/* SEE ALSO
|
||||
/* bounce(3) basic bounce service client interface
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstream.h>
|
||||
#include <name_mask.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <mail_queue.h>
|
||||
#include <post_mail.h>
|
||||
#include <mail_addr.h>
|
||||
#include <mail_error.h>
|
||||
#include <verp_sender.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "bounce_service.h"
|
||||
|
||||
#define STR vstring_str
|
||||
|
||||
/* bounce_notify_verp - send a bounce */
|
||||
|
||||
int bounce_notify_verp(char *service, char *queue_name,
|
||||
char *queue_id, char *recipient,
|
||||
char *verp_delims, int flush)
|
||||
{
|
||||
char *myname = "bounce_notify_verp";
|
||||
BOUNCE_INFO *bounce_info;
|
||||
int bounce_status = 0;
|
||||
int postmaster_status;
|
||||
VSTREAM *bounce;
|
||||
int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
|
||||
var_notify_classes);
|
||||
char *postmaster;
|
||||
VSTRING *verp_buf = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Sanity checks. We must be called only for undeliverable non-bounce
|
||||
* messages.
|
||||
*/
|
||||
if (*recipient == 0)
|
||||
msg_panic("%s: attempt to bounce a single bounce", myname);
|
||||
if (strcasecmp(recipient, mail_addr_double_bounce()) == 0)
|
||||
msg_panic("%s: attempt to bounce a double bounce", myname);
|
||||
|
||||
/*
|
||||
* Initialize. Open queue file, bounce log, etc.
|
||||
*/
|
||||
bounce_info = bounce_mail_init(service, queue_name, queue_id, flush);
|
||||
|
||||
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
|
||||
#define NULL_CLEANUP_FLAGS 0
|
||||
#define BOUNCE_HEADERS 1
|
||||
#define BOUNCE_ALL 0
|
||||
|
||||
/*
|
||||
* A non-bounce message was returned. Send a single bounce, one per
|
||||
* recipient.
|
||||
*/
|
||||
while (bounce_log_read(bounce_info->log_handle) != 0) {
|
||||
|
||||
/*
|
||||
* Notify the originator.
|
||||
*/
|
||||
verp_sender(verp_buf, verp_delims, recipient,
|
||||
bounce_info->log_handle->recipient);
|
||||
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf),
|
||||
NULL_CLEANUP_FLAGS)) != 0) {
|
||||
|
||||
/*
|
||||
* Send the bounce message header, some boilerplate text that
|
||||
* pretends that we are a polite mail system, the text with
|
||||
* reason for the bounce, and a copy of the original message.
|
||||
*/
|
||||
if (bounce_header(bounce, bounce_info, STR(verp_buf)) == 0
|
||||
&& bounce_boilerplate(bounce, bounce_info) == 0
|
||||
&& bounce_recipient_log(bounce, bounce_info) == 0
|
||||
&& bounce_header_dsn(bounce, bounce_info) == 0
|
||||
&& bounce_recipient_dsn(bounce, bounce_info) == 0)
|
||||
bounce_original(bounce, bounce_info, flush ?
|
||||
BOUNCE_ALL : BOUNCE_HEADERS);
|
||||
bounce_status = post_mail_fclose(bounce);
|
||||
} else
|
||||
bounce_status = 1;
|
||||
|
||||
/*
|
||||
* Stop at the first sign of trouble, instead of making the problem
|
||||
* worse.
|
||||
*/
|
||||
if (bounce_status != 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Mark this recipient as done.
|
||||
*/
|
||||
bounce_log_delrcpt(bounce_info->log_handle);
|
||||
|
||||
/*
|
||||
* Optionally, send a postmaster notice.
|
||||
*
|
||||
* This postmaster notice is not critical, so if it fails don't
|
||||
* retransmit the bounce that we just generated, just log a warning.
|
||||
*/
|
||||
#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
|
||||
#define WANT_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
|
||||
|
||||
if (WANT_IF_BOUNCE || WANT_IF_DELAY) {
|
||||
|
||||
/*
|
||||
* Send the text with reason for the bounce, and the headers of
|
||||
* the original message. Don't bother sending the boiler-plate
|
||||
* text. This postmaster notice is not critical, so if it fails
|
||||
* don't retransmit the bounce that we just generated, just log a
|
||||
* warning.
|
||||
*/
|
||||
postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
|
||||
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
postmaster,
|
||||
NULL_CLEANUP_FLAGS)) != 0) {
|
||||
if (bounce_header(bounce, bounce_info, postmaster) == 0
|
||||
&& bounce_recipient_log(bounce, bounce_info) == 0
|
||||
&& bounce_header_dsn(bounce, bounce_info) == 0
|
||||
&& bounce_recipient_dsn(bounce, bounce_info) == 0)
|
||||
bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
|
||||
postmaster_status = post_mail_fclose(bounce);
|
||||
} else
|
||||
postmaster_status = 1;
|
||||
|
||||
if (postmaster_status)
|
||||
msg_warn("postmaster notice failed while bouncing to %s",
|
||||
recipient);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine the completion status. Delete the bounce log file only when
|
||||
* the bounce was posted successfully, and only if we are bouncing for
|
||||
* real, not just warning.
|
||||
*/
|
||||
if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
|
||||
&& errno != ENOENT)
|
||||
msg_fatal("remove %s %s: %m", service, queue_id);
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
bounce_mail_free(bounce_info);
|
||||
vstring_free(verp_buf);
|
||||
|
||||
return (bounce_status);
|
||||
}
|
@@ -28,6 +28,11 @@ extern int bounce_append_service(char *, char *, char *, char *);
|
||||
*/
|
||||
extern int bounce_notify_service(char *, char *, char *, char *, int);
|
||||
|
||||
/*
|
||||
* bounce_notify_verp.c
|
||||
*/
|
||||
extern int bounce_notify_verp(char *, char *, char *, char *, char *, int);
|
||||
|
||||
/*
|
||||
* bounce_cleanup.c
|
||||
*/
|
||||
@@ -51,7 +56,7 @@ typedef struct {
|
||||
VSTREAM *orig_fp; /* open queue file */
|
||||
long orig_offs; /* start of content */
|
||||
time_t arrival_time; /* time of arrival */
|
||||
BOUNCE_LOG *log_handle; /* open logfile */
|
||||
BOUNCE_LOG *log_handle; /* open logfile */
|
||||
} BOUNCE_INFO;
|
||||
|
||||
extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int);
|
||||
|
@@ -179,6 +179,20 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf,
|
||||
state->errs |= CLEANUP_STAT_BAD;
|
||||
return;
|
||||
}
|
||||
} else if (type == REC_TYPE_VERP) {
|
||||
if (state->sender == 0 || *state->sender == 0) {
|
||||
state->errs |= CLEANUP_STAT_BAD;
|
||||
return;
|
||||
}
|
||||
if (len == 0) {
|
||||
buf = var_verp_delim;
|
||||
len = strlen(buf);
|
||||
}
|
||||
if (len == 2) {
|
||||
cleanup_out(state, type, buf, len);
|
||||
} else {
|
||||
state->errs |= CLEANUP_STAT_BAD;
|
||||
}
|
||||
} else {
|
||||
cleanup_out(state, type, buf, len);
|
||||
}
|
||||
|
@@ -106,6 +106,7 @@ char *var_prop_extension; /* propagate unmatched extension */
|
||||
char *var_always_bcc; /* big brother */
|
||||
int var_extra_rcpt_limit; /* recipient extract limit */
|
||||
char *var_rcpt_witheld; /* recipients not disclosed */
|
||||
char *var_verp_delim; /* default VERP delimiters */
|
||||
|
||||
CONFIG_INT_TABLE cleanup_int_table[] = {
|
||||
VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
|
||||
@@ -133,6 +134,7 @@ CONFIG_STR_TABLE cleanup_str_table[] = {
|
||||
VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
|
||||
VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
|
||||
VAR_RCPT_WITHELD, DEF_RCPT_WITHELD, &var_rcpt_witheld, 1, 0,
|
||||
VAR_VERP_DELIM, DEF_VERP_DELIM, &var_verp_delim, 2, 2,
|
||||
0,
|
||||
};
|
||||
|
||||
|
@@ -18,7 +18,8 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
|
||||
sent.c smtp_stream.c split_addr.c string_list.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 xtext.c bounce_log.c \
|
||||
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c
|
||||
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
|
||||
verp_sender.c
|
||||
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
|
||||
debug_peer.o debug_process.o defer.o deliver_completed.o \
|
||||
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
|
||||
@@ -38,7 +39,8 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
|
||||
sent.o smtp_stream.o split_addr.o string_list.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 xtext.o bounce_log.o \
|
||||
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o
|
||||
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
|
||||
verp_sender.o
|
||||
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
||||
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
|
||||
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
|
||||
@@ -54,7 +56,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
||||
recipient_list.h record.h resolve_clnt.h resolve_local.h \
|
||||
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
|
||||
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
|
||||
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h
|
||||
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h
|
||||
TESTSRC = rec2stream.c stream2rec.c recdump.c
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||
@@ -1036,6 +1038,11 @@ tok822_tree.o: ../../include/vstring.h
|
||||
tok822_tree.o: ../../include/vbuf.h
|
||||
tok822_tree.o: tok822.h
|
||||
tok822_tree.o: resolve_clnt.h
|
||||
verp_sender.o: verp_sender.c
|
||||
verp_sender.o: ../../include/sys_defs.h
|
||||
verp_sender.o: ../../include/vstring.h
|
||||
verp_sender.o: ../../include/vbuf.h
|
||||
verp_sender.o: verp_sender.h
|
||||
xtext.o: xtext.c
|
||||
xtext.o: ../../include/sys_defs.h
|
||||
xtext.o: ../../include/vstream.h
|
||||
|
@@ -14,6 +14,15 @@
|
||||
/* void (*callback)(int status, char *context);
|
||||
/* char *context;
|
||||
/*
|
||||
/* void abounce_flush_verp(flags, queue, id, sender, verp, callback, context)
|
||||
/* int flags;
|
||||
/* const char *queue;
|
||||
/* const char *id;
|
||||
/* const char *sender;
|
||||
/* const char *verp;
|
||||
/* void (*callback)(int status, char *context);
|
||||
/* char *context;
|
||||
/*
|
||||
/* void adefer_flush(flags, queue, id, sender, callback, context)
|
||||
/* int flags;
|
||||
/* const char *queue;
|
||||
@@ -22,6 +31,15 @@
|
||||
/* void (*callback)(int status, char *context);
|
||||
/* char *context;
|
||||
/*
|
||||
/* void adefer_flush_verp(flags, queue, id, sender, verp, callback, context)
|
||||
/* int flags;
|
||||
/* const char *queue;
|
||||
/* const char *id;
|
||||
/* const char *sender;
|
||||
/* const char *verp;
|
||||
/* void (*callback)(int status, char *context);
|
||||
/* char *context;
|
||||
/*
|
||||
/* void adefer_warn(flags, queue, id, sender, callback, context)
|
||||
/* int flags;
|
||||
/* const char *queue;
|
||||
@@ -38,10 +56,16 @@
|
||||
/* the specified sender, including the bounce log that was
|
||||
/* built with bounce_append().
|
||||
/*
|
||||
/* abounce_flush_verp() is like abounce_flush() but sends
|
||||
/* one VERP style notification per undeliverable recipient.
|
||||
/*
|
||||
/* adefer_flush() bounces the specified message to
|
||||
/* the specified sender, including the defer log that was
|
||||
/* built with defer_append().
|
||||
/*
|
||||
/* adefer_flush_verp() is like adefer_flush() but sends
|
||||
/* one VERP style notification per undeliverable recipient.
|
||||
/*
|
||||
/* adefer_warn() sends a "mail is delayed" notification to
|
||||
/* the specified sender, including the defer log that was
|
||||
/* built with defer_append().
|
||||
@@ -64,6 +88,8 @@
|
||||
/* file has the same name as the original message file.
|
||||
/* .IP sender
|
||||
/* The sender envelope address.
|
||||
/* .IP verp
|
||||
/* VERP delimiter characters.
|
||||
/* .IP callback
|
||||
/* Name of a routine that receives the notification status as
|
||||
/* documented for bounce_flush() or defer_flush().
|
||||
@@ -148,6 +174,60 @@ static void abounce_event(int unused_event, char *context)
|
||||
abounce_done(ap, mail_scan(ap->fp, "%d", &status) == 1 ? status : -1);
|
||||
}
|
||||
|
||||
/* abounce_request_verp - suspend pseudo thread until server reply event */
|
||||
|
||||
static void abounce_request_verp(const char *class, const char *service,
|
||||
int command, int flags,
|
||||
const char *queue, const char *id,
|
||||
const char *sender, const char *verp,
|
||||
ABOUNCE_FN callback,
|
||||
char *context)
|
||||
{
|
||||
ABOUNCE *ap;
|
||||
|
||||
/*
|
||||
* Save pseudo thread state. Connect to the server. Send the request and
|
||||
* suspend the pseudo thread until the server replies (or dies).
|
||||
*/
|
||||
ap = (ABOUNCE *) mymalloc(sizeof(*ap));
|
||||
ap->command = command;
|
||||
ap->flags = flags;
|
||||
ap->id = mystrdup(id);
|
||||
ap->callback = callback;
|
||||
ap->context = context;
|
||||
ap->fp = mail_connect_wait(class, service);
|
||||
|
||||
if (mail_print(ap->fp, "%d %d %s %s %s %s %s", command,
|
||||
flags, queue, id, sender, verp, MAIL_EOF) == 0
|
||||
&& vstream_fflush(ap->fp) == 0) {
|
||||
event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
|
||||
} else {
|
||||
abounce_done(ap, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/* abounce_flush_verp - asynchronous bounce flush */
|
||||
|
||||
void abounce_flush_verp(int flags, const char *queue, const char *id,
|
||||
const char *sender, const char *verp,
|
||||
ABOUNCE_FN callback, char *context)
|
||||
{
|
||||
abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE,
|
||||
BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
|
||||
callback, context);
|
||||
}
|
||||
|
||||
/* adefer_flush_verp - asynchronous defer flush */
|
||||
|
||||
void adefer_flush_verp(int flags, const char *queue, const char *id,
|
||||
const char *sender, const char *verp,
|
||||
ABOUNCE_FN callback, char *context)
|
||||
{
|
||||
abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
|
||||
BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
|
||||
callback, context);
|
||||
}
|
||||
|
||||
/* abounce_request - suspend pseudo thread until server reply event */
|
||||
|
||||
static void abounce_request(const char *class, const char *service,
|
||||
|
@@ -25,6 +25,9 @@ extern void abounce_flush(int, const char *, const char *, const char *, ABOUNCE
|
||||
extern void adefer_flush(int, const char *, const char *, const char *, ABOUNCE_FN, char *);
|
||||
extern void adefer_warn(int, const char *, const char *, const char *, ABOUNCE_FN, char *);
|
||||
|
||||
extern void abounce_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
|
||||
extern void adefer_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@@ -40,8 +40,8 @@ extern int vbounce_recip(int, const char *, const char *, const char *,
|
||||
*/
|
||||
#define BOUNCE_CMD_APPEND 0 /* append log */
|
||||
#define BOUNCE_CMD_FLUSH 1 /* send log */
|
||||
#define BOUNCE_CMD_WARN 2 /* send warning bounce, don't delete
|
||||
* log */
|
||||
#define BOUNCE_CMD_WARN 2 /* send warning, don't delete log */
|
||||
#define BOUNCE_CMD_VERP 3 /* send log, verp style */
|
||||
|
||||
/*
|
||||
* Flags.
|
||||
|
@@ -24,6 +24,9 @@
|
||||
/* BOUNCE_LOG *bounce_log_read(bp)
|
||||
/* BOUNCE_LOG *bp;
|
||||
/*
|
||||
/* BOUNCE_LOG *bounce_log_delrcpt(bp)
|
||||
/* BOUNCE_LOG *bp;
|
||||
/*
|
||||
/* void bounce_log_rewind(bp)
|
||||
/* BOUNCE_LOG *bp;
|
||||
/*
|
||||
@@ -31,8 +34,7 @@
|
||||
/* BOUNCE_LOG *bp;
|
||||
/* DESCRIPTION
|
||||
/* This module implements a bounce/defer logfile API. Information
|
||||
/* is sanitized for control and non-ASCII characters. Currently,
|
||||
/* only the reading end is implemented.
|
||||
/* is sanitized for control and non-ASCII characters.
|
||||
/*
|
||||
/* bounce_log_open() opens the named bounce or defer logfile
|
||||
/* and returns a handle that must be used for further access.
|
||||
@@ -47,6 +49,9 @@
|
||||
/* bounce_log_read() returns a null pointer when no recipient was read,
|
||||
/* otherwise it returns its argument.
|
||||
/*
|
||||
/* bounce_log_delrcpt() marks the last accessed recipient record as
|
||||
/* "deleted". This requires that the logfile is opened for update.
|
||||
/*
|
||||
/* bounce_log_rewind() is a helper that seeks to the first recipient
|
||||
/* in an open bounce or defer logfile (skipping over recipients that
|
||||
/* are marked as done). The result is 0 in case of success, -1 in case
|
||||
@@ -92,6 +97,7 @@
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
@@ -133,6 +139,7 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id,
|
||||
bp->fp = fp;
|
||||
bp->buf = vstring_alloc(100);
|
||||
bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0";
|
||||
bp->offset = 0;
|
||||
return (bp);
|
||||
}
|
||||
}
|
||||
@@ -145,7 +152,8 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
|
||||
char *text;
|
||||
char *cp;
|
||||
|
||||
while (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF) {
|
||||
while ((bp->offset = vstream_ftell(bp->fp)),
|
||||
(vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) {
|
||||
|
||||
if (STR(bp->buf)[0] == 0)
|
||||
continue;
|
||||
@@ -155,6 +163,12 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
|
||||
*/
|
||||
cp = printable(STR(bp->buf), '?');
|
||||
|
||||
/*
|
||||
* Skip over deleted recipients.
|
||||
*/
|
||||
if (*cp == BOUNCE_LOG_STAT_DELETED)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Find the recipient address.
|
||||
*/
|
||||
@@ -185,6 +199,21 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* bounce_log_delrcpt - mark recipient record as deleted */
|
||||
|
||||
BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *bp)
|
||||
{
|
||||
long current_offset;
|
||||
|
||||
current_offset = vstream_ftell(bp->fp);
|
||||
if (vstream_fseek(bp->fp, bp->offset, SEEK_SET) < 0)
|
||||
msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp));
|
||||
VSTREAM_PUTC(BOUNCE_LOG_STAT_DELETED, bp->fp);
|
||||
if (vstream_fseek(bp->fp, current_offset, SEEK_SET) < 0)
|
||||
msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp));
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/* bounce_log_close - close bounce reader stream */
|
||||
|
||||
int bounce_log_close(BOUNCE_LOG *bp)
|
||||
|
@@ -28,14 +28,18 @@ typedef struct {
|
||||
const char *recipient; /* final recipient */
|
||||
const char *status; /* recipient status */
|
||||
const char *text; /* why undeliverable */
|
||||
long offset; /* start of current record */
|
||||
} BOUNCE_LOG;
|
||||
|
||||
extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int);
|
||||
extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *);
|
||||
extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *);
|
||||
extern int bounce_log_close(BOUNCE_LOG *);
|
||||
|
||||
#define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET)
|
||||
|
||||
#define BOUNCE_LOG_STAT_DELETED 'D' /* deleted record */
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@@ -1271,6 +1271,14 @@ extern int var_qmqpd_timeout;
|
||||
#define DEF_QMTPD_ERR_SLEEP "5s"
|
||||
extern int var_qmqpd_err_sleep;
|
||||
|
||||
/*
|
||||
* VERP, more DJB intellectual cross-pollination. However, we prefer + as
|
||||
* the default recipient delimiter.
|
||||
*/
|
||||
#define VAR_VERP_DELIM "default_verp_delimiters"
|
||||
#define DEF_VERP_DELIM "+="
|
||||
extern char *var_verp_delim;
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010707"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010709"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@@ -56,6 +56,7 @@ REC_TYPE_NAME rec_type_names[] = {
|
||||
REC_TYPE_RRTO, "return_receipt",
|
||||
REC_TYPE_ERTO, "errors_to",
|
||||
REC_TYPE_PRIO, "priority",
|
||||
REC_TYPE_VERP, "verp_delimiters",
|
||||
REC_TYPE_END, "message_end",
|
||||
0, 0,
|
||||
};
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#define REC_TYPE_RRTO 'r' /* return-receipt, from headers */
|
||||
#define REC_TYPE_ERTO 'e' /* errors-to, from headers */
|
||||
#define REC_TYPE_PRIO 'P' /* priority */
|
||||
#define REC_TYPE_VERP 'V' /* VERP delimiters */
|
||||
|
||||
#define REC_TYPE_END 'E' /* terminator, required */
|
||||
|
||||
@@ -53,7 +54,7 @@
|
||||
* record groups. The first member in each set is the record type that
|
||||
* indicates the end of that record group.
|
||||
*/
|
||||
#define REC_TYPE_ENVELOPE "MCTFILSDRW"
|
||||
#define REC_TYPE_ENVELOPE "MCTFILSDRWV"
|
||||
#define REC_TYPE_CONTENT "XLN"
|
||||
#define REC_TYPE_EXTRACT "EDRPre"
|
||||
#define REC_TYPE_NOEXTRACT "E"
|
||||
|
@@ -67,7 +67,7 @@ char *split_addr(char *localpart, int delimiter)
|
||||
/*
|
||||
* Backwards compatibility: don't split owner-foo or foo-request.
|
||||
*/
|
||||
if (var_ownreq_special != 0) {
|
||||
if (delimiter == '-' && var_ownreq_special != 0) {
|
||||
if (strncasecmp(localpart, "owner-", 6) == 0)
|
||||
return (0);
|
||||
if ((len = strlen(localpart) - 8) > 0
|
||||
|
83
postfix/src/global/verp_sender.c
Normal file
83
postfix/src/global/verp_sender.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* verp_sender 3
|
||||
/* SUMMARY
|
||||
/* quote local part of mailbox
|
||||
/* SYNOPSIS
|
||||
/* #include <verp_sender.h>
|
||||
/*
|
||||
/* VSTRING *verp_sender(dst, delims, sender, recipient)
|
||||
/* VSTRING *dst;
|
||||
/* const char *delims;
|
||||
/* const char *sender;
|
||||
/* const char *recipient;
|
||||
/* DESCRIPTION
|
||||
/* verp_sender() encodes the recipient address in the sender
|
||||
/* address, using the specified delimiters. For example,
|
||||
/* with delims +=, sender \fIprefix@origin\fR, and
|
||||
/* recipient \fIuser@domain\fR the result is
|
||||
/* \fIprefix+user=domain@origin\fR.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP dst
|
||||
/* The result. The buffer is null terminated.
|
||||
/* .IP delims
|
||||
/* VERP formatting characters.
|
||||
/* .IP sender
|
||||
/* Sender envelope address.
|
||||
/* .IP recipient
|
||||
/* Recipient envelope address.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstring.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <verp_sender.h>
|
||||
|
||||
/* verp_sender - encode recipient into envelope sender address */
|
||||
|
||||
VSTRING *verp_sender(VSTRING *buf, const char *delimiters,
|
||||
const char *sender, const char *recipient)
|
||||
{
|
||||
int send_local_len;
|
||||
int rcpt_local_len;
|
||||
const char *cp;
|
||||
|
||||
/*
|
||||
* Change prefix@origin into prefix+user=domain@origin.
|
||||
*/
|
||||
send_local_len = ((cp = strrchr(sender, '@')) ?
|
||||
cp - sender : strlen(sender));
|
||||
rcpt_local_len = ((cp = strrchr(recipient, '@')) ?
|
||||
cp - recipient : strlen(recipient));
|
||||
vstring_strncpy(buf, sender, send_local_len);
|
||||
VSTRING_ADDCH(buf, delimiters[0] & 0xff);
|
||||
vstring_strncat(buf, recipient, rcpt_local_len);
|
||||
if (recipient[rcpt_local_len] && recipient[rcpt_local_len + 1]) {
|
||||
VSTRING_ADDCH(buf, delimiters[1] & 0xff);
|
||||
vstring_strcat(buf, recipient + rcpt_local_len + 1);
|
||||
}
|
||||
if (sender[send_local_len] && sender[send_local_len + 1]) {
|
||||
VSTRING_ADDCH(buf, '@');
|
||||
vstring_strcat(buf, sender + send_local_len + 1);
|
||||
}
|
||||
VSTRING_TERMINATE(buf);
|
||||
return (buf);
|
||||
}
|
35
postfix/src/global/verp_sender.h
Normal file
35
postfix/src/global/verp_sender.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _VERP_SENDER_H_INCLUDED_
|
||||
#define _VERP_SENDER_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* verp_sender 3h
|
||||
/* SUMMARY
|
||||
/* encode recipient into sender, VERP style
|
||||
/* SYNOPSIS
|
||||
/* #include "verp_sender.h"
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <vstring.h>
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTRING *verp_sender(VSTRING *, const char *, const char *, const char *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
#endif
|
@@ -267,6 +267,7 @@ struct QMGR_MESSAGE {
|
||||
char *queue_name; /* queue name */
|
||||
char *queue_id; /* queue file */
|
||||
char *sender; /* complete address */
|
||||
char *verp_delims; /* VERP delimiters */
|
||||
char *errors_to; /* error report address */
|
||||
char *return_receipt; /* confirm receipt address */
|
||||
char *filter_xport; /* filtering transport */
|
||||
|
@@ -275,12 +275,21 @@ void qmgr_active_done(QMGR_MESSAGE *message)
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: bounce %s", myname, message->queue_id);
|
||||
abounce_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
if (message->verp_delims == 0)
|
||||
abounce_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
else
|
||||
abounce_flush_verp(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
message->verp_delims,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -353,12 +362,21 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
|
||||
if (event_time() > message->arrival_time + var_max_queue_time) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: too old, bouncing %s", myname, message->queue_id);
|
||||
adefer_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
if (message->verp_delims == 0)
|
||||
adefer_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
else
|
||||
adefer_flush_verp(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
message->verp_delims,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
return;
|
||||
} else if (message->warn_time > 0
|
||||
&& event_time() > message->warn_time) {
|
||||
|
@@ -68,6 +68,7 @@
|
||||
#include <recipient_list.h>
|
||||
#include <mail_params.h>
|
||||
#include <deliver_request.h>
|
||||
#include <verp_sender.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -124,6 +125,22 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
||||
QMGR_RCPT *recipient;
|
||||
QMGR_MESSAGE *message = entry->message;
|
||||
char *cp;
|
||||
VSTRING *sender_buf = 0;
|
||||
char *sender;
|
||||
|
||||
/*
|
||||
* If variable envelope return path is requested, change prefix+@origin
|
||||
* into prefix+user=domain@origin. Note that with VERP there is only one
|
||||
* recipient per delivery.
|
||||
*/
|
||||
if (message->verp_delims == 0) {
|
||||
sender = message->sender;
|
||||
} else {
|
||||
sender_buf = vstring_alloc(100);
|
||||
verp_sender(sender_buf, message->verp_delims,
|
||||
message->sender, list.info->address);
|
||||
sender = vstring_str(sender_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* With mail transports that accept only one recipient per delivery, the
|
||||
@@ -136,9 +153,11 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
||||
message->queue_name, message->queue_id,
|
||||
message->data_offset, message->data_size,
|
||||
(cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 :
|
||||
entry->queue->name, message->sender,
|
||||
entry->queue->name, sender,
|
||||
message->errors_to, message->return_receipt,
|
||||
message->arrival_time);
|
||||
if (sender_buf != 0)
|
||||
vstring_free(sender_buf);
|
||||
for (recipient = list.info; recipient < list.info + list.len; recipient++)
|
||||
mail_print(stream, "%ld %s", recipient->offset, recipient->address);
|
||||
mail_print(stream, "%s", "0");
|
||||
|
@@ -161,6 +161,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
||||
message->warn_offset = 0;
|
||||
message->warn_time = 0;
|
||||
message->rcpt_offset = 0;
|
||||
message->verp_delims = 0;
|
||||
message->unread_offset = 0;
|
||||
qmgr_rcpt_list_init(&message->rcpt_list);
|
||||
message->rcpt_count = 0;
|
||||
@@ -423,6 +424,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
message->warn_offset = curr_offset;
|
||||
message->warn_time = atol(start);
|
||||
}
|
||||
} else if (rec_type == REC_TYPE_VERP) {
|
||||
if (strlen(start) != 2) {
|
||||
msg_warn("%s: bad VERP record length: \"%s\"",
|
||||
message->queue_id, start);
|
||||
} else {
|
||||
message->single_rcpt = 1;
|
||||
message->verp_delims = mystrdup(start);
|
||||
}
|
||||
}
|
||||
} while (rec_type > 0 && rec_type != REC_TYPE_END);
|
||||
|
||||
@@ -902,6 +911,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
||||
myfree(message->queue_name);
|
||||
if (message->sender)
|
||||
myfree(message->sender);
|
||||
if (message->verp_delims)
|
||||
myfree(message->verp_delims);
|
||||
if (message->errors_to)
|
||||
myfree(message->errors_to);
|
||||
if (message->return_receipt)
|
||||
|
@@ -136,6 +136,7 @@ qmgr_deliver.o: ../../include/mail_proto.h
|
||||
qmgr_deliver.o: ../../include/recipient_list.h
|
||||
qmgr_deliver.o: ../../include/mail_params.h
|
||||
qmgr_deliver.o: ../../include/deliver_request.h
|
||||
qmgr_deliver.o: ../../include/verp_sender.h
|
||||
qmgr_deliver.o: qmgr.h
|
||||
qmgr_deliver.o: ../../include/scan_dir.h
|
||||
qmgr_deliver.o: ../../include/maps.h
|
||||
|
@@ -227,6 +227,7 @@ struct QMGR_MESSAGE {
|
||||
char *queue_name; /* queue name */
|
||||
char *queue_id; /* queue file */
|
||||
char *sender; /* complete address */
|
||||
char *verp_delims; /* VERP delimiters */
|
||||
char *errors_to; /* error report address */
|
||||
char *return_receipt; /* confirm receipt address */
|
||||
char *filter_xport; /* filtering transport */
|
||||
|
@@ -275,12 +275,21 @@ void qmgr_active_done(QMGR_MESSAGE *message)
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: bounce %s", myname, message->queue_id);
|
||||
abounce_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
if (message->verp_delims == 0)
|
||||
abounce_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
else
|
||||
abounce_flush_verp(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
message->verp_delims,
|
||||
qmgr_active_done_2_bounce_flush,
|
||||
(char *) message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -353,12 +362,21 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
|
||||
if (event_time() > message->arrival_time + var_max_queue_time) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: too old, bouncing %s", myname, message->queue_id);
|
||||
adefer_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
if (message->verp_delims == 0)
|
||||
adefer_flush(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
else
|
||||
adefer_flush_verp(BOUNCE_FLAG_KEEP,
|
||||
message->queue_name,
|
||||
message->queue_id,
|
||||
message->errors_to,
|
||||
message->verp_delims,
|
||||
qmgr_active_done_3_defer_flush,
|
||||
(char *) message);
|
||||
return;
|
||||
} else if (message->warn_time > 0
|
||||
&& event_time() > message->warn_time) {
|
||||
|
@@ -63,6 +63,7 @@
|
||||
#include <recipient_list.h>
|
||||
#include <mail_params.h>
|
||||
#include <deliver_request.h>
|
||||
#include <verp_sender.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -119,6 +120,22 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
||||
QMGR_RCPT *recipient;
|
||||
QMGR_MESSAGE *message = entry->message;
|
||||
char *cp;
|
||||
VSTRING *sender_buf = 0;
|
||||
char *sender;
|
||||
|
||||
/*
|
||||
* If variable envelope return path is requested, change prefix+@origin
|
||||
* into prefix+user=domain@origin. Note that with VERP there is only one
|
||||
* recipient per delivery.
|
||||
*/
|
||||
if (message->verp_delims == 0) {
|
||||
sender = message->sender;
|
||||
} else {
|
||||
sender_buf = vstring_alloc(100);
|
||||
verp_sender(sender_buf, message->verp_delims,
|
||||
message->sender, list.info->address);
|
||||
sender = vstring_str(sender_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* With mail transports that accept only one recipient per delivery, the
|
||||
@@ -131,9 +148,11 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
|
||||
message->queue_name, message->queue_id,
|
||||
message->data_offset, message->data_size,
|
||||
(cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 :
|
||||
entry->queue->name, message->sender,
|
||||
entry->queue->name, sender,
|
||||
message->errors_to, message->return_receipt,
|
||||
message->arrival_time);
|
||||
if (sender_buf != 0)
|
||||
vstring_free(sender_buf);
|
||||
for (recipient = list.info; recipient < list.info + list.len; recipient++)
|
||||
mail_print(stream, "%ld %s", recipient->offset, recipient->address);
|
||||
mail_print(stream, "%s", "0");
|
||||
|
@@ -151,6 +151,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
|
||||
message->warn_offset = 0;
|
||||
message->warn_time = 0;
|
||||
message->rcpt_offset = 0;
|
||||
message->verp_delims = 0;
|
||||
qmgr_rcpt_list_init(&message->rcpt_list);
|
||||
return (message);
|
||||
}
|
||||
@@ -303,6 +304,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
message->warn_offset = curr_offset;
|
||||
message->warn_time = atol(start);
|
||||
}
|
||||
} else if (rec_type == REC_TYPE_VERP) {
|
||||
if (strlen(start) != 2) {
|
||||
msg_warn("%s: bad VERP record length: \"%s\"",
|
||||
message->queue_id, start);
|
||||
} else {
|
||||
message->single_rcpt = 1;
|
||||
message->verp_delims = mystrdup(start);
|
||||
}
|
||||
}
|
||||
} while (rec_type > 0 && rec_type != REC_TYPE_END);
|
||||
|
||||
@@ -737,6 +746,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
||||
myfree(message->queue_name);
|
||||
if (message->sender)
|
||||
myfree(message->sender);
|
||||
if (message->verp_delims)
|
||||
myfree(message->verp_delims);
|
||||
if (message->errors_to)
|
||||
myfree(message->errors_to);
|
||||
if (message->return_receipt)
|
||||
|
@@ -210,11 +210,34 @@ static void qmqpd_read_content(QMQPD_STATE *state)
|
||||
|
||||
static void qmqpd_copy_sender(QMQPD_STATE *state)
|
||||
{
|
||||
char *end_prefix;
|
||||
char *end_origin;
|
||||
int verp_requested;
|
||||
|
||||
/*
|
||||
* If the sender address looks like prefix-@origin-@[], then request
|
||||
* variable envelope return path delivery, with an envelope sender
|
||||
* address of prefix@origin, and with VERP delimiters of - and =. This
|
||||
* way, the recipients will see envelope sender addresses that look like:
|
||||
* prefix-user=domain@origin.
|
||||
*/
|
||||
state->where = "receiving sender address";
|
||||
netstring_get(state->client, state->buf, var_line_limit);
|
||||
verp_requested = ((end_prefix = strstr(STR(state->buf), "-@")) != 0
|
||||
&& (end_origin = strstr(end_prefix + 2, "-@")) != 0
|
||||
&& strncmp(end_origin + 2, "[]", 2) == 0
|
||||
&& vstring_end(state->buf) == end_origin + 4);
|
||||
if (verp_requested) {
|
||||
memcpy(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
|
||||
vstring_truncate(state->buf, end_origin - STR(state->buf) - 1);
|
||||
}
|
||||
if (state->err == CLEANUP_STAT_OK
|
||||
&& REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0)
|
||||
state->err = CLEANUP_STAT_WRITE;
|
||||
if (verp_requested)
|
||||
if (state->err == CLEANUP_STAT_OK
|
||||
&& rec_put(state->cleanup, REC_TYPE_VERP, "-=", 2) < 0)
|
||||
state->err = CLEANUP_STAT_WRITE;
|
||||
state->sender = mystrndup(STR(state->buf), LEN(state->buf));
|
||||
}
|
||||
|
||||
|
@@ -76,6 +76,11 @@
|
||||
/* \fBdebug_peer_level\fR configuration parameters instead.
|
||||
/* .IP "\fB-U\fR (ignored)"
|
||||
/* Initial user submission.
|
||||
/* .IP \fB-V\fR
|
||||
/* Variable Envelope Return Path. Given an envelope sender address
|
||||
/* \fIprefix\fR-@\fIorigin\fR, each recipient \fIuser@domain\fR
|
||||
/* receives mail with a personalized envelope sender address
|
||||
/* \fIprefix\fB-\fIuser=domain\fR@\fIorigin\fR.
|
||||
/* .IP \fB-bd\fR
|
||||
/* Go into daemon mode. This mode of operation is implemented by
|
||||
/* executing the \fBpostfix start\fR command.
|
||||
@@ -319,6 +324,11 @@ static void sendmail_cleanup(void);
|
||||
|
||||
#define SM_FLAG_DEFAULT (SM_FLAG_AEOF)
|
||||
|
||||
/*
|
||||
* VERP support.
|
||||
*/
|
||||
char *verp_delims;
|
||||
|
||||
/*
|
||||
* Silly little macros (SLMs).
|
||||
*/
|
||||
@@ -414,6 +424,10 @@ static void enqueue(const int flags, const char *sender, const char *full_name,
|
||||
if (full_name || (full_name = fullname()) != 0)
|
||||
rec_fputs(dst, REC_TYPE_FULL, full_name);
|
||||
rec_fputs(dst, REC_TYPE_FROM, saved_sender);
|
||||
if (verp_delims && *saved_sender == 0)
|
||||
msg_fatal("-V option requires non-null sender address");
|
||||
if (verp_delims)
|
||||
rec_fputs(dst, REC_TYPE_VERP, verp_delims);
|
||||
if (recipients) {
|
||||
for (cpp = recipients; *cpp != 0; cpp++) {
|
||||
tree = tok822_parse(*cpp);
|
||||
@@ -794,7 +808,7 @@ int main(int argc, char **argv)
|
||||
optind++;
|
||||
continue;
|
||||
}
|
||||
if ((c = GETOPT(argc, argv, "B:C:F:GIN:R:UX:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
|
||||
if ((c = GETOPT(argc, argv, "B:C:F:GIN:R:UVX:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
|
||||
break;
|
||||
switch (c) {
|
||||
default:
|
||||
@@ -817,6 +831,9 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
case 'R': /* DSN */
|
||||
break;
|
||||
case 'V': /* VERP */
|
||||
verp_delims = "";
|
||||
break;
|
||||
case 'b':
|
||||
switch (*optarg) {
|
||||
default:
|
||||
|
@@ -32,8 +32,8 @@
|
||||
/* STANDARDS
|
||||
/* RFC 821 (SMTP protocol)
|
||||
/* RFC 1123 (Host requirements)
|
||||
/* RFC 1651 (SMTP service extensions)
|
||||
/* RFC 1652 (8bit-MIME transport)
|
||||
/* RFC 1869 (SMTP service extensions)
|
||||
/* RFC 1854 (SMTP Pipelining)
|
||||
/* RFC 1870 (Message Size Declaration)
|
||||
/* RFC 1985 (ETRN command)
|
||||
@@ -363,6 +363,12 @@ char *smtpd_path;
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
|
||||
/*
|
||||
* VERP command name.
|
||||
*/
|
||||
#define VERP_CMD "XVERP"
|
||||
#define VERP_CMD_LEN 5
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
@@ -459,6 +465,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
|
||||
}
|
||||
#endif
|
||||
smtpd_chat_reply(state, "250-%s", VERP_CMD);
|
||||
smtpd_chat_reply(state, "250 8BITMIME");
|
||||
return (0);
|
||||
}
|
||||
@@ -626,6 +633,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
char *err;
|
||||
int narg;
|
||||
char *arg;
|
||||
char *verp_delims = 0;
|
||||
|
||||
state->msg_size = 0;
|
||||
|
||||
@@ -680,12 +688,27 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
} else if (strcasecmp(arg, VERP_CMD) == 0) {
|
||||
verp_delims = "";
|
||||
} else if (strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0
|
||||
&& arg[VERP_CMD_LEN] == '=') {
|
||||
verp_delims = arg + VERP_CMD_LEN + 1;
|
||||
if (strlen(verp_delims) != 2) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad %s parameter: %s",
|
||||
VERP_CMD, arg);
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "555 Unsupported option: %s", arg);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (verp_delims && argv[2].strval[0] == 0) {
|
||||
smtpd_chat_reply(state, "503 Error: XVERP requires non-null sender");
|
||||
return (-1);
|
||||
}
|
||||
state->time = time((time_t *) 0);
|
||||
if (SMTPD_STAND_ALONE(state) == 0
|
||||
&& var_smtpd_delay_reject == 0
|
||||
@@ -718,6 +741,8 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
if (*var_filter_xport)
|
||||
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
|
||||
rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
|
||||
if (verp_delims)
|
||||
rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
|
||||
state->sender = mystrdup(argv[2].strval);
|
||||
smtpd_chat_reply(state, "250 Ok");
|
||||
return (0);
|
||||
|
@@ -8,7 +8,7 @@
|
||||
/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
|
||||
/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
|
||||
/*
|
||||
/* \fBqmqp-sink\fR [\fB-cv\fR]
|
||||
/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
|
||||
/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR
|
||||
/* DESCRIPTION
|
||||
/* \fIqmqp-sink\fR listens on the named host (or address) and port.
|
||||
|
Reference in New Issue
Block a user