multiple Postfix instances. Text by Victor Duchovny, Morgan
Stanley. File: README_FILES/FILTER_README.
-Open problems:
+20020510
+
+ Feature: header/body filters now log the origin of the
+ message that is being rejected. Files: smtpd/smtpd.c,
+ qmqpd/qmqpd.c, pickup/pickup.c, cleanup/cleanup_envelope.c,
+ cleanup/cleanup_message.c. Requested by Craig Sanders, if
+ I remember correctly.
+
+ Feature: the Postfix SMTP client now passes on MIME body
+ type information (8bit, 7bit) received via SMTP, via MIME
+ headers, or via the sendmail command line. Files:
+ global/deliver_request.c, smtpd/smtpd.c, sendmail/sendmail.c,
+ cleanup/cleanup_envelope.c, cleanup/cleanup_message.c,
+ cleanup/cleanup_extracted.c, *qmgr/qmgr_message.c,
+ *qmgr/qmgr_deliver.c, smtp/smtp_proto.c, lmtp/lmtp_proto.c.
+
+20020511
+
+ Feature: bounces now specify the proper MIME encoding (8bit,
+ 7bit), depending on the MIME body type information received
+ via SMTP, via MIME headers, or via the sendmail command
+ line. Files: global/bounce.c, global/defer.c, global/abounce.c,
+ bounce/bounce_service.c, bounce/bounce_notify_util.c.
- Low: smtpd should reply with the original recipient address,
- or it should at least externalize it.
+20020512
+
+ Cleanup: the SMTP client logged and bounced the CNAME
+ expanded recipient address, and thereby complicated trouble
+ shooting. File: src/smtp_proto.c.
+
+ Bugfix: the SMTP and LMTP clients bounced the quoted
+ recipient address, resulting in too much quoting in bounce
+ reports. Files: src/smtp_proto.c, lmtp/lmtp_proto.c.
+
+Open problems:
Low: all table lookups should consistently use internalized
(unquoted) or externalized (quoted) forms as lookup keys.
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix snapshot 1.1.9-20020512
+=========================================================
+
+The Postfix SMTP client no longer uses the CNAME expanded recipient
+address when logging delivery or when bouncing mail. This makes
+trouble shooting somewhat easier.
+
+Postfix snapshot 1.1.9-20020512 queue files contain records that
+are incompatible with "postqueue -r" on all Postfix versions prior
+to 1.1 and release candidates. This happens whenever the sender
+specifies MIME body type information via the SMTP `MAIL FROM'
+command, via the `sendmail -B' command line option, or via the
+Content-Transfer-Encoding: message header.
+
+Postfix snapshot 1.1.9-20020512 queue files may contain records
+that are incompatible with "postqueue -r" on previous 1.1 Postfix
+versions and release candidates. This happens whenever the sender
+specifies the MIME body type only via the Content-Transfer-Encoding:
+message header, and not via `MAIL FROM' or `sendmail -B'.
+
+Major changes with Postfix snapshot 1.1.9-20020512
+==================================================
+
+The Postfix SMTP and LMTP clients now properly pass on the MIME
+body type information (7BIT or 8BITMIME), provided that the sender
+properly specifies MIME body type information via the SMTP MAIL
+FROM command, via the sendmail -B command line option, or via MIME
+message headers. This includes mail that is returned as undeliverable.
+Implementing MIME body type propagation was a low priority because
+qmail didn't implement this, either. However, Postfix will not
+convert 8BITMIME content into 7BIT, and probably never will.
+
Incompatible changes with Postfix snapshot 1.1.9-20020509
=========================================================
The appearance of user@domain1@domain2 addresses has changed. In
mail headers, such addresses are now properly quoted as
-"user@domain1"@domain2. This quoted form is now also expected on
-the left-hand side of virtual and canonical lookup tables, but only
-by some of the Postfix components. For now, it is better not to
-use user@domain1@domain2 address forms on the left-hand side of
-lookup tables.
+"user@domain1"@domain2. As a side effect, this quoted form is now
+also expected on the left-hand side of virtual and canonical lookup
+tables, but only by some of the Postfix components. For now, it
+is better not to use user@domain1@domain2 address forms on the
+left-hand side of lookup tables.
Incompatible changes with Postfix snapshot 1.1.8-20020508
=========================================================
<html> <head> </head> <body> <pre>
-
BOUNCE(8) BOUNCE(8)
<b>NAME</b>
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
<a href="http://www.faqs.org/rfcs/rfc1894.html">RFC 1894</a> (Delivery Status Notifications)
+ <a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (Format of Internet Message Bodies)
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
P.O. Box 704
Yorktown Heights, NY 10598, USA
- 1
-
+ BOUNCE(8)
</pre> </body> </html>
<html> <head> </head> <body> <pre>
-
LMTP(8) LMTP(8)
<b>NAME</b>
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<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/rfc1870.html">RFC 1870</a> (Message Size Declaration)
<a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
P.O. Box 830688, MC34
Richardson, TX 75083, USA
- 1
-
+ LMTP(8)
</pre> </body> </html>
The following options are recognized:
- <b>-B</b> <i>body_type</i> (ignored)
- The message body MIME type. Currently, Postfix
- implements <b>just-send-eight</b>.
+ <b>-B</b> <i>body_type</i>
+ The message body MIME type: <b>7BIT</b> or <b>8BITMIME</b>.
<b>-C</b> <i>config_file</i> (ignored :-)
The path name of the <b>sendmail.cf</b> file. Postfix con-
figuration files are kept in <b>/etc/postfix</b>.
<b>-F</b> <i>full_name</i>
- Set the sender full name. This is used only with
+ Set the sender full name. This is used only with
messages that have no <b>From:</b> message header.
<b>-G</b> (ignored)
- Gateway (relay) submission, as opposed to initial
+ Gateway (relay) submission, as opposed to initial
user submission.
- <b>-I</b> Initialize alias database. See the <b>newaliases</b> com-
+ <b>-I</b> Initialize alias database. See the <b>newaliases</b> com-
mand above.
<b>-L</b> <i>label</i> (ignored)
- The logging label. Use the <b>syslog</b><i>_</i><b>name</b> configura-
+ The logging label. Use the <b>syslog</b><i>_</i><b>name</b> configura-
tion parameter instead.
<b>-N</b> <i>dsn</i> (ignored)
- Delivery status notification control. Currently,
+ Delivery status notification control. Currently,
Postfix does not implement <b>DSN</b>.
<b>-R</b> <i>return_limit</i> (ignored)
- Limit the size of bounced mail. Use the
- <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b> configuration parameter instead.
+ Limit the size of bounced mail. Use the
+ <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b> configuration parameter instead.
<b>-X</b> <i>log_file</i> (ignored)
- Log mailer traffic. Use the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> and
- <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> configuration parameters instead.
+ Log mailer traffic. Use the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> and
+ <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> configuration parameters instead.
<b>-U</b> (ignored)
Initial user submission.
- <b>-V</b> Variable Envelope Return Path. Given an envelope
- sender address of the form <i>owner-listname</i>@<i>origin</i>,
- each recipient <i>user</i>@<i>domain</i> receives mail with a
+ <b>-V</b> Variable Envelope Return Path. Given an envelope
+ sender address of the form <i>owner-listname</i>@<i>origin</i>,
+ each recipient <i>user</i>@<i>domain</i> receives mail with a
personalized envelope sender address.
- By default, the personalized envelope sender
- address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
- default <b>+</b> and <b>=</b> characters are configurable with
- the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame-
+ By default, the personalized envelope sender
+ address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
+ default <b>+</b> and <b>=</b> characters are configurable with
+ the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame-
ter.
<b>-V</b><i>xy</i> As <b>-V</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter char-
- acters, instead of the characters specified with
- the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame-
+ acters, instead of the characters specified with
+ the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame-
ter.
- <b>-bd</b> Go into daemon mode. This mode of operation is
+ <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-
- dard output. In stand-alone SMTP server mode, UCE
- restrictions and access controls are disabled by
- default. To enable them, run the process as the
+ <b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands
+ from standard input, and write responses to stan-
+ dard output. In stand-alone SMTP server mode, UCE
+ restrictions and access controls are disabled by
+ default. To enable them, run the process as the
<b>mail</b><i>_</i><b>owner</b> user.
- This mode of operation is implemented by running
+ 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)
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 executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
<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
+ Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. This option accepts only
- <i>site</i> names that are eligible for the "fast flush"
- service, and is implemented by executing the
+ <i>site</i> names that are eligible for the "fast flush"
+ service, and is implemented by executing the
<a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. See <a href="flushd.8.html"><b>flush</b>(8)</a> for more infor-
mation 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>
<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>
/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>
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>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b>
- The VERP delimiter characters that are used when
- the <b>-V</b> command line option is specified without
+ The VERP delimiter characters that are used when
+ the <b>-V</b> command line option is specified without
delimiter characters.
<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 list specifies the
- domains that Postfix accepts in the SMTP <b>ETRN</b>
+ vice (default: all domains that this system is
+ willing to relay mail to). This list specifies the
+ domains that Postfix accepts in the SMTP <b>ETRN</b>
request and in the <b>sendmail</b> <b>-qR</b> command.
<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>verp</b><i>_</i><b>delimiter</b><i>_</i><b>filter</b>
- The characters that Postfix accepts as VERP delim-
+ The characters that Postfix accepts as VERP delim-
iter characters.
<b>SEE</b> <b>ALSO</b>
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>
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<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/rfc1870.html">RFC 1870</a> (Message Size Declaration)
<a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
<a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
controlled by parameters in the \fBmain.cf\fR configuration file.
The following options are recognized:
-.IP "\fB-B \fIbody_type\fR (ignored)"
-The message body MIME type. Currently, Postfix implements
-\fBjust-send-eight\fR.
+.IP "\fB-B \fIbody_type\fR"
+The message body MIME type: \fB7BIT\fR or \fB8BITMIME\fR.
.IP "\fB-C \fIconfig_file\fR (ignored :-)"
The path name of the \fBsendmail.cf\fR file. Postfix configuration
files are kept in \fB/etc/postfix\fR.
.nf
RFC 822 (ARPA Internet Text Messages)
RFC 1894 (Delivery Status Notifications)
+RFC 2045 (Format of Internet Message Bodies)
.SH DIAGNOSTICS
.ad
.fi
.nf
RFC 821 (SMTP protocol)
RFC 1651 (SMTP service extensions)
+RFC 1652 (8bit-MIME transport)
RFC 1870 (Message Size Declaration)
RFC 2033 (LMTP protocol)
RFC 2197 (Pipelining)
.nf
RFC 821 (SMTP protocol)
RFC 1651 (SMTP service extensions)
+RFC 1652 (8bit-MIME transport)
RFC 1870 (Message Size Declaration)
RFC 2197 (Pipelining)
RFC 2554 (AUTH command)
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: ../../include/mail_proto.h
+bounce_notify_util.o: ../../include/iostuff.h
+bounce_notify_util.o: ../../include/attr.h
bounce_notify_util.o: bounce_service.h
bounce_notify_verp.o: bounce_notify_verp.c
bounce_notify_verp.o: ../../include/sys_defs.h
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* RFC 1894 (Delivery Status Notifications)
+/* RFC 2045 (Format of Internet Message Bodies)
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* BUGS
static VSTRING *queue_id;
static VSTRING *queue_name;
static VSTRING *recipient;
+static VSTRING *encoding;
static VSTRING *sender;
static VSTRING *verp_delims;
static VSTRING *why;
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
- ATTR_TYPE_END) != 4) {
+ ATTR_TYPE_END) != 5) {
msg_warn("malformed request");
return (-1);
}
return (-1);
}
if (msg_verbose)
- msg_info("bounce_notify_proto: service=%s queue=%s id=%s sender=%s",
- service_name, STR(queue_name), STR(queue_id), STR(sender));
+ msg_info("bounce_notify_proto: service=%s queue=%s id=%s encoding=%s sender=%s",
+ service_name, STR(queue_name), STR(queue_id),
+ STR(encoding), STR(sender));
/*
* On request by the client, set up a trap to delete the log file in case
* Execute the request.
*/
return (bounce_notify_service(service_name, STR(queue_name),
- STR(queue_id), STR(sender), flush));
+ STR(queue_id), STR(encoding),
+ STR(sender), flush));
}
/* bounce_verp_proto - bounce_notify server protocol, VERP style */
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
- ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
- ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
- ATTR_TYPE_END) != 5) {
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+ ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+ ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
+ ATTR_TYPE_END) != 6) {
msg_warn("malformed request");
return (-1);
}
return (-1);
}
if (msg_verbose)
- msg_info("%s: service=%s queue=%s id=%s sender=%s delim=%s",
+ msg_info("%s: service=%s queue=%s id=%s encoding=%s sender=%s delim=%s",
myname, service_name, STR(queue_name), STR(queue_id),
- STR(sender), STR(verp_delims));
+ STR(encoding), STR(sender), STR(verp_delims));
/*
* On request by the client, set up a trap to delete the log file in case
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));
+ STR(queue_id), STR(encoding),
+ STR(sender), flush));
} else
return (bounce_notify_verp(service_name, STR(queue_name),
- STR(queue_id), STR(sender),
- STR(verp_delims), flush));
+ STR(queue_id), STR(encoding),
+ STR(sender), STR(verp_delims), flush));
}
/* bounce_service - parse bounce command type and delegate */
queue_id = vstring_alloc(10);
queue_name = vstring_alloc(10);
recipient = vstring_alloc(10);
+ encoding = vstring_alloc(10);
sender = vstring_alloc(10);
verp_delims = vstring_alloc(10);
why = vstring_alloc(10);
/* SYNOPSIS
/* #include "bounce_service.h"
/*
-/* int bounce_notify_service(queue_name, queue_id, sender, flush)
+/* int bounce_notify_service(queue_name, queue_id, encoding,
+/* sender, flush)
/* char *queue_name;
/* char *queue_id;
+/* char *encoding;
/* char *sender;
/* int flush;
/* DESCRIPTION
/* bounce_notify_service - send a bounce */
int bounce_notify_service(char *service, char *queue_name,
- char *queue_id, char *recipient, int flush)
+ char *queue_id, char *encoding,
+ char *recipient, int flush)
{
BOUNCE_INFO *bounce_info;
int bounce_status = 1;
/*
* Initialize. Open queue file, bounce log, etc.
*/
- bounce_info = bounce_mail_init(service, queue_name, queue_id, flush);
+ bounce_info = bounce_mail_init(service, queue_name, queue_id,
+ encoding, flush);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
/* .in -4
/* } BOUNCE_INFO;
/*
-/* BOUNCE_INFO *bounce_mail_init(service, queue_name, queue_id, flush)
+/* BOUNCE_INFO *bounce_mail_init(service, queue_name, queue_id,
+/* encoding, flush)
/* const char *service;
/* const char *queue_name;
/* const char *queue_id;
+/* const char *encoding;
/* int flush;
/*
/* void bounce_mail_free(bounce_info)
#include <mail_error.h>
#include <bounce_log.h>
#include <mail_date.h>
+#include <mail_proto.h>
/* Application-specific. */
/* bounce_mail_init - initialize */
BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name,
- const char *queue_id, int flush)
+ const char *queue_id,
+ const char *encoding, int flush)
{
BOUNCE_INFO *bounce_info;
int rec_type;
bounce_info->service = service;
bounce_info->queue_name = queue_name;
bounce_info->queue_id = queue_id;
+ if (strcmp(encoding, MAIL_ATTR_ENC_8BIT) == 0) {
+ bounce_info->mime_encoding = "8bit";
+ } else if (strcmp(encoding, MAIL_ATTR_ENC_7BIT) == 0) {
+ bounce_info->mime_encoding = "7bit";
+ } else {
+ if (strcmp(encoding, MAIL_ATTR_ENC_NONE) != 0)
+ msg_warn("%s: unknown encoding: %.200s",
+ bounce_info->queue_id, encoding);
+ bounce_info->mime_encoding = 0;
+ }
bounce_info->flush = flush;
bounce_info->buf = vstring_alloc(100);
bounce_info->arrival_time = 0;
post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
"multipart/report", "delivery-status");
post_mail_fprintf(bounce, "\tboundary=\"%s\"", bounce_info->mime_boundary);
+ if (bounce_info->mime_encoding)
+ post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
+ bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
"Undelivered Message Headers" : "Undelivered Message");
post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
"text/rfc822-headers" : "message/rfc822");
+ if (bounce_info->mime_encoding)
+ post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
+ bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
/*
/* bounce_notify_verp - send a bounce */
int bounce_notify_verp(char *service, char *queue_name,
- char *queue_id, char *recipient,
+ char *queue_id, char *encoding,
+ char *recipient,
char *verp_delims, int flush)
{
char *myname = "bounce_notify_verp";
/*
* Initialize. Open queue file, bounce log, etc.
*/
- bounce_info = bounce_mail_init(service, queue_name, queue_id, flush);
+ bounce_info = bounce_mail_init(service, queue_name, queue_id,
+ encoding, flush);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
/*
* bounce_notify_service.c
*/
-extern int bounce_notify_service(char *, char *, char *, char *, int);
+extern int bounce_notify_service(char *, char *, char *, char *, char *, int);
/*
* bounce_notify_verp.c
*/
-extern int bounce_notify_verp(char *, char *, char *, char *, char *, int);
+extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *, int);
/*
* bounce_cleanup.c
const char *service; /* bounce or defer */
const char *queue_name; /* incoming, etc. */
const char *queue_id; /* base name */
+ const char *mime_encoding; /* null or encoding */
const char *mime_boundary; /* for MIME */
int flush; /* 0=defer, other=bounce */
VSTRING *buf; /* scratch pad */
BOUNCE_LOG *log_handle; /* open logfile */
} BOUNCE_INFO;
-extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int);
+extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, int);
extern void bounce_mail_free(BOUNCE_INFO *);
extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *);
extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *);
cleanup.o: ../../include/rec_type.h
cleanup.o: ../../include/mail_server.h
cleanup.o: cleanup.h
+cleanup.o: ../../include/nvtable.h
+cleanup.o: ../../include/htable.h
+cleanup.o: ../../include/mymalloc.h
cleanup.o: ../../include/maps.h
cleanup.o: ../../include/tok822.h
cleanup.o: ../../include/resolve_clnt.h
cleanup_api.o: ../../include/mail_stream.h
cleanup_api.o: cleanup.h
cleanup_api.o: ../../include/argv.h
+cleanup_api.o: ../../include/nvtable.h
+cleanup_api.o: ../../include/htable.h
cleanup_api.o: ../../include/maps.h
cleanup_api.o: ../../include/dict.h
cleanup_api.o: ../../include/tok822.h
cleanup_envelope.o: ../../include/vbuf.h
cleanup_envelope.o: ../../include/vstream.h
cleanup_envelope.o: ../../include/mymalloc.h
+cleanup_envelope.o: ../../include/stringops.h
+cleanup_envelope.o: ../../include/nvtable.h
+cleanup_envelope.o: ../../include/htable.h
cleanup_envelope.o: ../../include/record.h
cleanup_envelope.o: ../../include/rec_type.h
cleanup_envelope.o: ../../include/cleanup_user.h
cleanup_extracted.o: ../../include/vstream.h
cleanup_extracted.o: ../../include/argv.h
cleanup_extracted.o: ../../include/mymalloc.h
+cleanup_extracted.o: ../../include/nvtable.h
+cleanup_extracted.o: ../../include/htable.h
cleanup_extracted.o: ../../include/cleanup_user.h
cleanup_extracted.o: ../../include/record.h
cleanup_extracted.o: ../../include/rec_type.h
cleanup_extracted.o: ../../include/mail_params.h
cleanup_extracted.o: ../../include/ext_prop.h
+cleanup_extracted.o: ../../include/mail_proto.h
+cleanup_extracted.o: ../../include/iostuff.h
+cleanup_extracted.o: ../../include/attr.h
cleanup_extracted.o: cleanup.h
cleanup_extracted.o: ../../include/maps.h
cleanup_extracted.o: ../../include/dict.h
cleanup_init.o: ../../include/vbuf.h
cleanup_init.o: ../../include/vstream.h
cleanup_init.o: ../../include/argv.h
+cleanup_init.o: ../../include/nvtable.h
+cleanup_init.o: ../../include/htable.h
+cleanup_init.o: ../../include/mymalloc.h
cleanup_init.o: ../../include/maps.h
cleanup_init.o: ../../include/dict.h
cleanup_init.o: ../../include/tok822.h
cleanup_map11.o: ../../include/quote_822_local.h
cleanup_map11.o: ../../include/quote_flags.h
cleanup_map11.o: cleanup.h
+cleanup_map11.o: ../../include/nvtable.h
+cleanup_map11.o: ../../include/htable.h
cleanup_map11.o: ../../include/tok822.h
cleanup_map11.o: ../../include/resolve_clnt.h
cleanup_map11.o: ../../include/been_here.h
cleanup_map1n.o: ../../include/quote_flags.h
cleanup_map1n.o: ../../include/been_here.h
cleanup_map1n.o: cleanup.h
+cleanup_map1n.o: ../../include/nvtable.h
+cleanup_map1n.o: ../../include/htable.h
cleanup_map1n.o: ../../include/tok822.h
cleanup_map1n.o: ../../include/resolve_clnt.h
cleanup_map1n.o: ../../include/mail_stream.h
cleanup_masquerade.o: ../../include/quote_flags.h
cleanup_masquerade.o: cleanup.h
cleanup_masquerade.o: ../../include/vstream.h
+cleanup_masquerade.o: ../../include/nvtable.h
cleanup_masquerade.o: ../../include/maps.h
cleanup_masquerade.o: ../../include/dict.h
cleanup_masquerade.o: ../../include/been_here.h
cleanup_message.o: ../../include/argv.h
cleanup_message.o: ../../include/split_at.h
cleanup_message.o: ../../include/mymalloc.h
+cleanup_message.o: ../../include/stringops.h
+cleanup_message.o: ../../include/nvtable.h
+cleanup_message.o: ../../include/htable.h
cleanup_message.o: ../../include/record.h
cleanup_message.o: ../../include/rec_type.h
cleanup_message.o: ../../include/cleanup_user.h
cleanup_message.o: ../../include/mail_addr.h
cleanup_message.o: ../../include/is_header.h
cleanup_message.o: ../../include/ext_prop.h
+cleanup_message.o: ../../include/mail_proto.h
+cleanup_message.o: ../../include/iostuff.h
+cleanup_message.o: ../../include/attr.h
cleanup_message.o: cleanup.h
cleanup_message.o: ../../include/maps.h
cleanup_message.o: ../../include/dict.h
cleanup_out.o: ../../include/mail_params.h
cleanup_out.o: cleanup.h
cleanup_out.o: ../../include/argv.h
+cleanup_out.o: ../../include/nvtable.h
+cleanup_out.o: ../../include/htable.h
+cleanup_out.o: ../../include/mymalloc.h
cleanup_out.o: ../../include/maps.h
cleanup_out.o: ../../include/dict.h
cleanup_out.o: ../../include/tok822.h
cleanup_out_recipient.o: ../../include/vstring.h
cleanup_out_recipient.o: ../../include/vbuf.h
cleanup_out_recipient.o: ../../include/vstream.h
+cleanup_out_recipient.o: ../../include/nvtable.h
+cleanup_out_recipient.o: ../../include/htable.h
+cleanup_out_recipient.o: ../../include/mymalloc.h
cleanup_out_recipient.o: ../../include/maps.h
cleanup_out_recipient.o: ../../include/dict.h
cleanup_out_recipient.o: ../../include/tok822.h
cleanup_rewrite.o: cleanup.h
cleanup_rewrite.o: ../../include/vstream.h
cleanup_rewrite.o: ../../include/argv.h
+cleanup_rewrite.o: ../../include/nvtable.h
+cleanup_rewrite.o: ../../include/htable.h
+cleanup_rewrite.o: ../../include/mymalloc.h
cleanup_rewrite.o: ../../include/maps.h
cleanup_rewrite.o: ../../include/dict.h
cleanup_rewrite.o: ../../include/been_here.h
cleanup_state.o: ../../include/vstring.h
cleanup_state.o: ../../include/vbuf.h
cleanup_state.o: ../../include/argv.h
+cleanup_state.o: ../../include/htable.h
cleanup_state.o: ../../include/been_here.h
cleanup_state.o: ../../include/mail_params.h
cleanup_state.o: cleanup.h
cleanup_state.o: ../../include/vstream.h
+cleanup_state.o: ../../include/nvtable.h
cleanup_state.o: ../../include/maps.h
cleanup_state.o: ../../include/dict.h
cleanup_state.o: ../../include/tok822.h
#include <vstring.h>
#include <vstream.h>
#include <argv.h>
+#include <nvtable.h>
/*
* Global library.
int end_seen; /* REC_TYPE_END seen */
int rcpt_count; /* recipient count */
char *reason; /* failure reason */
+ NVTABLE *attr; /* queue file attribute list */
} CLEANUP_STATE;
/*
/* These flags control the handling of data errors, and must be set
/* before processing the first message record.
/* .IP CLEANUP_FLAG_BOUNCE
-/* The cleanup server is responsible for returning undeliverable
+/* The cleanup server is responsible for returning undeliverable
/* mail (too many hops, message too large) to the sender.
/* .IP CLEANUP_FLAG_FILTER
-/* Enable header/body filtering. This should be enabled only with mail
-/* that enters Postfix, not with locally forwarded mail or with bounce
+/* Enable header/body filtering. This should be enabled only with mail
+/* that enters Postfix, not with locally forwarded mail or with bounce
/* messages.
/* .IP CLEANUP_FLAG_EXTRACT
/* Extract recipients from message headers when no recipients are
* that the runtime error handler can clean up in case of problems.
*/
state->handle = mail_stream_file(MAIL_QUEUE_INCOMING,
- MAIL_CLASS_PUBLIC, var_queue_service, 0);
+ MAIL_CLASS_PUBLIC, var_queue_service, 0);
state->dst = state->handle->stream;
cleanup_path = mystrdup(VSTREAM_PATH(state->dst));
state->queue_id = mystrdup(state->handle->id);
{
char *junk;
int status;
+ char *encoding;
/*
* Ignore recipient extraction alarms if (a) we did (not need to) extract
"%s", state->reason ? state->reason :
cleanup_strerror(state->errs)) == 0
&& bounce_flush(BOUNCE_FLAG_CLEAN, MAIL_QUEUE_INCOMING,
- state->queue_id, state->sender) == 0) {
+ state->queue_id,
+ (encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) ?
+ encoding : MAIL_ATTR_ENC_NONE,
+ state->sender) == 0) {
state->errs = 0;
} else {
if (var_soft_bounce == 0) {
#include <vstring.h>
#include <vstream.h>
#include <mymalloc.h>
+#include <stringops.h>
+#include <nvtable.h>
/* Global library. */
static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf, int len)
{
+ char *attr_name;
+ char *attr_value;
+ const char *error_text;
+
if (type == REC_TYPE_MESG) {
if (state->sender == 0 || state->time == 0) {
msg_warn("%s: missing sender or time envelope record",
state->errs |= CLEANUP_STAT_BAD;
return;
}
+ } else if (type == REC_TYPE_ATTR) {
+ if (state->attr->used >= var_qattr_count_limit) {
+ msg_warn("%s: queue file attribute count exceeds safety limit: %d",
+ state->queue_id, var_qattr_count_limit);
+ state->errs |= CLEANUP_STAT_BAD;
+ return;
+ }
+ cleanup_out(state, type, buf, len);
+ if ((error_text = split_nameval(buf, &attr_name, &attr_value)) != 0) {
+ msg_warn("%s: malformed attribute: %s: %.100s",
+ state->queue_id, error_text, buf);
+ state->errs |= CLEANUP_STAT_BAD;
+ return;
+ }
+ nvtable_update(state->attr, attr_name, attr_value);
} else {
cleanup_out(state, type, buf, len);
}
#include <vstream.h>
#include <argv.h>
#include <mymalloc.h>
+#include <nvtable.h>
/* Global library. */
#include <rec_type.h>
#include <mail_params.h>
#include <ext_prop.h>
+#include <mail_proto.h>
/* Application-specific. */
void cleanup_extracted(CLEANUP_STATE *state, int type, char *buf, int len)
{
+ const char *encoding;
/*
* Start the extracted segment.
*/
cleanup_out_string(state, REC_TYPE_XTRA, "");
+ /*
+ * Older Postfix versions didn't emit encoding information, so this
+ * record can only be optional. Putting this before the mandatory
+ * Return-Receipt-To and Errors-To ensures that the queue manager will
+ * pick up the content encoding before starting deliveries.
+ */
+ if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ENCODING, encoding);
+
/*
* Always emit Return-Receipt-To and Errors-To records, and always emit
* them ahead of extracted recipients, so that the queue manager does not
int var_extra_rcpt_limit; /* recipient extract limit */
char *var_rcpt_witheld; /* recipients not disclosed */
char *var_masq_classes; /* what to masquerade */
+int var_qattr_count_limit; /* named attribute limit */
CONFIG_INT_TABLE cleanup_int_table[] = {
VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0,
VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
VAR_EXTRA_RCPT_LIMIT, DEF_EXTRA_RCPT_LIMIT, &var_extra_rcpt_limit, 0, 0,
+ VAR_QATTR_COUNT_LIMIT, DEF_QATTR_COUNT_LIMIT, &var_qattr_count_limit, 1, 0,
0,
};
#include <argv.h>
#include <split_at.h>
#include <mymalloc.h>
+#include <stringops.h>
+#include <nvtable.h>
/* Global library. */
#include <mail_addr.h>
#include <is_header.h>
#include <ext_prop.h>
+#include <mail_proto.h>
/* Application-specific. */
{
const char *optional_text = value + strcspn(value, " \t");
int command_len = optional_text - value;
+ const char *origin;
while (*optional_text && ISSPACE(*optional_text))
optional_text++;
state->reason = mystrdup(*optional_text ? optional_text :
cleanup_strerror(CLEANUP_STAT_CONT));
state->errs |= CLEANUP_STAT_CONT;
- msg_info("%s: reject: %s %.200s; from=<%s> to=<%s>: %s",
- state->queue_id, context, buf, state->sender,
+ if ((origin = nvtable_find(state->attr, MAIL_ATTR_ORIGIN)) == 0)
+ origin = MAIL_ATTR_ORG_NONE;
+ msg_info("%s: reject: %s %.200s from %s; from=<%s> to=<%s>: %s",
+ state->queue_id, context, buf, origin, state->sender,
state->recip ? state->recip : "unknown",
state->reason);
return (CLEANUP_ACT_KEEP);
{
char *myname = "cleanup_header";
HEADER_OPTS *hdr_opts;
+ char *hdrval;
+ struct code_map {
+ const char *name;
+ const char *encoding;
+ };
+ static struct code_map code_map[] = { /* RFC 2045 */
+ "7bit", MAIL_ATTR_ENC_7BIT,
+ "8bit", MAIL_ATTR_ENC_8BIT,
+ "binary", MAIL_ATTR_ENC_8BIT, /* XXX Violation */
+ "quoted-printable", MAIL_ATTR_ENC_7BIT,
+ "base64", MAIL_ATTR_ENC_7BIT,
+ 0,
+ };
+ struct code_map *cmp;
if (msg_verbose)
msg_info("%s: '%s'", myname, vstring_str(state->header_buf));
*/
else {
state->headers_seen |= (1 << hdr_opts->type);
+ hdrval = vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2;
+ while (ISSPACE(*hdrval))
+ hdrval++;
+ trimblanks(hdrval, 0);
if (hdr_opts->type == HDR_MESSAGE_ID)
- msg_info("%s: message-id=%s", state->queue_id,
- vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2);
+ msg_info("%s: message-id=%s", state->queue_id, hdrval);
if (hdr_opts->type == HDR_RESENT_MESSAGE_ID)
- msg_info("%s: resent-message-id=%s", state->queue_id,
- vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2);
+ msg_info("%s: resent-message-id=%s", state->queue_id, hdrval);
if (hdr_opts->type == HDR_RECEIVED)
if (++state->hop_count >= var_hopcount_limit)
state->errs |= CLEANUP_STAT_HOPS;
+ if (hdr_opts->type == HDR_CONTENT_TRANSFER_ENCODING) {
+ if (nvtable_find(state->attr, MAIL_ATTR_ENCODING) == 0) {
+ for (cmp = code_map; cmp->name != 0; cmp++) {
+ if (strcasecmp(hdrval, cmp->name) == 0) {
+ nvtable_update(state->attr, MAIL_ATTR_ENCODING,
+ cmp->encoding);
+ break;
+ }
+ }
+ }
+ }
if (CLEANUP_OUT_OK(state)) {
if (hdr_opts->flags & HDR_OPT_RR)
state->resent = "Resent-";
#include <mymalloc.h>
#include <vstring.h>
#include <argv.h>
+#include <htable.h>
/* Global library. */
state->end_seen = 0;
state->rcpt_count = 0;
state->reason = 0;
+ state->attr = nvtable_create(10);
return (state);
}
been_here_free(state->dups);
if (state->reason)
myfree(state->reason);
+ nvtable_free(state->attr);
myfree((char *) state);
}
/* SYNOPSIS
/* #include <abounce.h>
/*
-/* void abounce_flush(flags, queue, id, sender, callback, context)
+/* void abounce_flush(flags, queue, id, encoding, sender, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* void (*callback)(int status, char *context);
/* char *context;
/*
-/* void abounce_flush_verp(flags, queue, id, sender, verp, callback, context)
+/* void abounce_flush_verp(flags, queue, id, encoding, sender, verp, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* const char *verp;
/* void (*callback)(int status, char *context);
/* char *context;
/*
-/* void adefer_flush(flags, queue, id, sender, callback, context)
+/* void adefer_flush(flags, queue, id, encoding, sender, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* void (*callback)(int status, char *context);
/* char *context;
/*
-/* void adefer_flush_verp(flags, queue, id, sender, verp, callback, context)
+/* void adefer_flush_verp(flags, queue, id, encoding, sender, verp, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* const char *verp;
/* void (*callback)(int status, char *context);
/* char *context;
/*
-/* void adefer_warn(flags, queue, id, sender, callback, context)
+/* void adefer_warn(flags, queue, id, encoding, sender, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* void (*callback)(int status, char *context);
/* char *context;
/* .IP id
/* The message queue id if the original message file. The bounce log
/* file has the same name as the original message file.
+/* .IP encoding
+/* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
/* .IP sender
/* The sender envelope address.
/* .IP verp
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,
+ const char *encoding,
+ const char *sender,
+ const char *verp,
ABOUNCE_FN callback,
char *context)
{
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp,
ATTR_TYPE_END) == 0
/* 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)
+ const char *encoding, const char *sender,
+ const char *verp, ABOUNCE_FN callback,
+ char *context)
{
abounce_request_verp(MAIL_CLASS_PRIVATE, var_bounce_service,
- BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
- callback, context);
+ BOUNCE_CMD_VERP, flags, queue, id, encoding,
+ 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)
+ const char *encoding, const char *sender,
+ const char *verp, ABOUNCE_FN callback,
+ char *context)
{
abounce_request_verp(MAIL_CLASS_PRIVATE, var_defer_service,
- BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
- callback, context);
+ BOUNCE_CMD_VERP, flags, queue, id, encoding,
+ sender, verp, callback, context);
}
/* abounce_request - suspend pseudo thread until server reply event */
static void abounce_request(const char *class, const char *service,
int command, int flags,
const char *queue, const char *id,
- const char *sender,
- ABOUNCE_FN callback,
- char *context)
+ const char *encoding, const char *sender,
+ ABOUNCE_FN callback, char *context)
{
ABOUNCE *ap;
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_END) == 0
&& vstream_fflush(ap->fp) == 0) {
/* abounce_flush - asynchronous bounce flush */
void abounce_flush(int flags, const char *queue, const char *id,
- const char *sender, ABOUNCE_FN callback, char *context)
+ const char *encoding, const char *sender,
+ ABOUNCE_FN callback, char *context)
{
abounce_request(MAIL_CLASS_PRIVATE, var_bounce_service, BOUNCE_CMD_FLUSH,
- flags, queue, id, sender, callback, context);
+ flags, queue, id, encoding, sender, callback, context);
}
/* adefer_flush - asynchronous defer flush */
void adefer_flush(int flags, const char *queue, const char *id,
- const char *sender, ABOUNCE_FN callback, char *context)
+ const char *encoding, const char *sender,
+ ABOUNCE_FN callback, char *context)
{
abounce_request(MAIL_CLASS_PRIVATE, var_defer_service, BOUNCE_CMD_FLUSH,
- flags, queue, id, sender, callback, context);
+ flags, queue, id, encoding, sender, callback, context);
}
/* adefer_warn - send copy of defer log to sender as warning bounce */
void adefer_warn(int flags, const char *queue, const char *id,
- const char *sender, ABOUNCE_FN callback, char *context)
+ const char *encoding, const char *sender,
+ ABOUNCE_FN callback, char *context)
{
abounce_request(MAIL_CLASS_PRIVATE, var_defer_service, BOUNCE_CMD_WARN,
- flags, queue, id, sender, callback, context);
+ flags, queue, id, encoding, sender, callback, context);
}
*/
typedef void (*ABOUNCE_FN) (int, char *);
-extern void abounce_flush(int, const char *, const char *, const char *, ABOUNCE_FN, char *);
-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(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
+extern void adefer_flush(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
+extern void adefer_warn(int, const char *, 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 *);
+extern void abounce_flush_verp(int, const char *, 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 *, const char *, ABOUNCE_FN, char *);
/* LICENSE
/* .ad
/* const char *format;
/* va_list ap;
/*
-/* int bounce_flush(flags, queue, id, sender)
+/* int bounce_flush(flags, queue, id, encoding, sender)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/* DESCRIPTION
/* This module implements the client interface to the message
/* .IP id
/* The message queue id if the original message file. The bounce log
/* file has the same name as the original message file.
+/* .IP encoding
+/* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
/* .IP sender
/* The sender envelope address.
/* .IP relay
/* bounce_flush - flush the bounce log and deliver to the sender */
int bounce_flush(int flags, const char *queue, const char *id,
- const char *sender)
+ const char *encoding, const char *sender)
{
/*
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_END) == 0) {
return (0);
const char *,...);
extern int vbounce_append(int, const char *, const char *, const char *,
time_t, const char *, va_list);
-extern int bounce_flush(int, const char *, const char *, const char *);
+extern int bounce_flush(int, const char *, const char *, const char *, const char *);
extern int PRINTFLIKE(8, 9) bounce_recip(int, const char *, const char *,
const char *, const char *,
/* const char *format;
/* va_list ap;
/*
-/* int defer_flush(flags, queue, id, sender)
+/* int defer_flush(flags, queue, id, encoding, sender)
/* int flags;
/* const char *queue;
/* const char *id;
+/* const char *encoding;
/* const char *sender;
/*
/* int defer_warn(flags, queue, id, sender)
/* .IP recipient
/* A recipient address that is being deferred. The domain part
/* of the address is marked dead (for a limited amount of time).
+/* .IP encoding
+/* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
/* .IP sender
/* The sender envelope address.
/* .IP relay
/* defer_flush - flush the defer log and deliver to the sender */
int defer_flush(int flags, const char *queue, const char *id,
- const char *sender)
+ const char *encoding, const char *sender)
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
- ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
- ATTR_TYPE_END) == 0) {
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+ ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+ ATTR_TYPE_END) == 0) {
return (0);
} else {
return (-1);
const char *sender)
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
- ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
- ATTR_TYPE_END) == 0) {
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+ ATTR_TYPE_END) == 0) {
return (0);
} else {
return (-1);
const char *, time_t, const char *,...);
extern int vdefer_append(int, const char *, const char *, const char *,
time_t, const char *, va_list);
-extern int defer_flush(int, const char *, const char *, const char *);
+extern int defer_flush(int, const char *, const char *, const char *, const char *);
extern int defer_warn(int, const char *, const char *, const char *);
/* long data_offset;
/* long data_size;
/* char *nexthop;
+/* char *encoding;
/* char *sender;
/* char *errors_to;
/* char *return_receipt;
static VSTRING *queue_name;
static VSTRING *queue_id;
static VSTRING *nexthop;
+ static VSTRING *encoding;
static VSTRING *address;
static VSTRING *errors_to;
static VSTRING *return_receipt;
queue_name = vstring_alloc(10);
queue_id = vstring_alloc(10);
nexthop = vstring_alloc(10);
+ encoding = vstring_alloc(10);
address = vstring_alloc(10);
errors_to = vstring_alloc(10);
return_receipt = vstring_alloc(10);
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset,
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, &request->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, return_receipt,
ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
- ATTR_TYPE_END) != 10)
+ ATTR_TYPE_END) != 11)
return (-1);
if (mail_open_ok(vstring_str(queue_name),
vstring_str(queue_id), &st, &path) == 0)
request->queue_name = mystrdup(vstring_str(queue_name));
request->queue_id = mystrdup(vstring_str(queue_id));
request->nexthop = mystrdup(vstring_str(nexthop));
+ request->encoding = mystrdup(vstring_str(encoding));
request->sender = mystrdup(vstring_str(address));
request->errors_to = mystrdup(vstring_str(errors_to));
request->return_receipt = mystrdup(vstring_str(return_receipt));
request->queue_name = 0;
request->queue_id = 0;
request->nexthop = 0;
+ request->encoding = 0;
request->sender = 0;
request->errors_to = 0;
request->return_receipt = 0;
myfree(request->queue_id);
if (request->nexthop)
myfree(request->nexthop);
+ if (request->encoding)
+ myfree(request->encoding);
if (request->sender)
myfree(request->sender);
if (request->errors_to)
long data_offset; /* offset to message */
long data_size; /* message size */
char *nexthop; /* next hop name */
+ char *encoding; /* content encoding */
char *sender; /* envelope sender */
char *errors_to; /* error report address */
char *return_receipt; /* confirm receipt address */
"Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
"Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP,
"Cc", HDR_CC, HDR_OPT_XRECIP,
+ "Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, 0,
"Content-Length", HDR_CONTENT_LENGTH, HDR_OPT_DROP,
"Delivered-To", HDR_DELIVERED_TO, 0,
"Date", HDR_DATE, 0,
#define DEF_DB_READ_BUF (128 *1024)
extern int var_db_read_buf;
+ /*
+ * Named queue file attributes.
+ */
+#define VAR_QATTR_COUNT_LIMIT "queue_file_attribute_count_limit"
+#define DEF_QATTR_COUNT_LIMIT 100
+extern int var_qattr_count_limit;
+
/* LICENSE
/* .ad
/* .fi
#define MAIL_ATTR_TRANSPORT "transport"
#define MAIL_ATTR_NEXTHOP "nexthop"
+ /*
+ * The following attribute names are stored in queue files. Changing this
+ * means lots of work to maintain backwards compatibility with queued mail.
+ */
+#define MAIL_ATTR_ENCODING "encoding" /* internal encoding */
+#define MAIL_ATTR_ENC_8BIT "8bit" /* 8BITMIME equivalent */
+#define MAIL_ATTR_ENC_7BIT "7bit" /* 7BIT equivalent */
+#define MAIL_ATTR_ENC_NONE "" /* encoding unknown */
+#define MAIL_ATTR_CLIENT_NAME "client_name" /* client hostname */
+#define MAIL_ATTR_CLIENT_ADDR "client_address" /* client address */
+#define MAIL_ATTR_HELO_NAME "helo_name" /* SMTP helo name */
+#define MAIL_ATTR_ORIGIN "message_origin" /* hostname[address] */
+#define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */
+#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */
+
/* LICENSE
/* .ad
/* .fi
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20020509"
+#define MAIL_RELEASE_DATE "20020512"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.9-" MAIL_RELEASE_DATE
* size record.
*/
rec_fprintf(stream, REC_TYPE_TIME, "%ld", (long) now);
+ rec_fprintf(stream, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ORIGIN, MAIL_ATTR_ORG_LOCAL);
rec_fputs(stream, REC_TYPE_FROM, sender);
rec_fputs(stream, REC_TYPE_RCPT, recipient);
rec_fputs(stream, REC_TYPE_MESG, "");
* The types of records that I expect to see while processing different
* record groups. The first member in each set is the record type that
* indicates the end of that record group.
+ *
+ * XXX A records in the extracted segment are generated only by the cleanup
+ * server, and are not supposed to be present in locally submitted mail, as
+ * this is "postfix internal" information. However, the pickup server has to
+ * allow for the presence of A records in the extracted segment, because it
+ * can be requested to re-process already queued mail with `postsuper -r'.
*/
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA"
#define REC_TYPE_CONTENT "XLN"
-#define REC_TYPE_EXTRACT "EDROPre" /* NOT A */
+#define REC_TYPE_EXTRACT "EDROPreA"
#define REC_TYPE_NOEXTRACT "E"
/*
lmtp_proto.o: ../../include/mark_corrupt.h
lmtp_proto.o: ../../include/quote_821_local.h
lmtp_proto.o: ../../include/quote_flags.h
+lmtp_proto.o: ../../include/mail_proto.h
+lmtp_proto.o: ../../include/iostuff.h
+lmtp_proto.o: ../../include/attr.h
lmtp_proto.o: lmtp.h
lmtp_proto.o: ../../include/argv.h
lmtp_proto.o: lmtp_sasl.h
/* STANDARDS
/* RFC 821 (SMTP protocol)
/* RFC 1651 (SMTP service extensions)
+/* RFC 1652 (8bit-MIME transport)
/* RFC 1870 (Message Size Declaration)
/* RFC 2033 (LMTP protocol)
/* RFC 2197 (Pipelining)
#include <off_cvt.h>
#include <mark_corrupt.h>
#include <quote_821_local.h>
+#include <mail_proto.h>
/* Application-specific. */
* Macros for readability. XXX Aren't LMTP addresses supposed to be case
* insensitive?
*/
-#define REWRITE_ADDRESS(addr) do { \
- if (*(addr)) { \
- quote_821_local(state->scratch, addr, QUOTE_FLAG_8BITCLEAN); \
- myfree(addr); \
- addr = mystrdup(vstring_str(state->scratch)); \
- lowercase(addr); \
+#define REWRITE_ADDRESS(dst, src) do { \
+ if (*(src)) { \
+ quote_821_local(dst, src, QUOTE_FLAG_8BITCLEAN); \
+ lowercase(vstring_str(dst)); \
+ } else { \
+ vstring_strcpy(dst, src); \
} \
} while (0)
* Build the MAIL FROM command.
*/
case LMTP_STATE_MAIL:
- if (*request->sender)
- REWRITE_ADDRESS(request->sender);
- vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
- if (state->features & LMTP_FEATURE_SIZE)
+ REWRITE_ADDRESS(state->scratch, request->sender);
+ vstring_sprintf(next_command, "MAIL FROM:<%s>",
+ vstring_str(state->scratch));
+ if (state->features & LMTP_FEATURE_SIZE) /* RFC 1652 */
vstring_sprintf_append(next_command, " SIZE=%lu",
request->data_size);
+ if (state->features & LMTP_FEATURE_8BITMIME) {
+ if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
+ vstring_strcat(next_command, " BODY=8BITMIME");
+ else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
+ vstring_strcat(next_command, " BODY=7BIT");
+ else if (strcmp(request->encoding, MAIL_ATTR_ENC_NONE) != 0)
+ msg_warn("%s: unknown content encoding: %s",
+ request->queue_id, request->encoding);
+ }
next_state = LMTP_STATE_RCPT;
break;
*/
case LMTP_STATE_RCPT:
rcpt = request->rcpt_list.info + send_rcpt;
- REWRITE_ADDRESS(rcpt->address);
- vstring_sprintf(next_command, "RCPT TO:<%s>", rcpt->address);
+ REWRITE_ADDRESS(state->scratch, rcpt->address);
+ vstring_sprintf(next_command, "RCPT TO:<%s>",
+ vstring_str(state->scratch));
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
next_state = LMTP_STATE_DATA;
break;
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/resolve_local.h
qmgr_message.o: ../../include/verp_sender.h
+qmgr_message.o: ../../include/mail_proto.h
+qmgr_message.o: ../../include/iostuff.h
+qmgr_message.o: ../../include/attr.h
qmgr_message.o: ../../include/resolve_clnt.h
qmgr_message.o: qmgr.h
qmgr_message.o: ../../include/scan_dir.h
long data_offset; /* data seek offset */
char *queue_name; /* queue name */
char *queue_id; /* queue file */
+ char *encoding; /* content encoding */
char *sender; /* complete address */
char *verp_delims; /* VERP delimiters */
char *errors_to; /* error report address */
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_2_bounce_flush,
(char *) message);
abounce_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
message->verp_delims,
qmgr_active_done_2_bounce_flush,
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_3_defer_flush,
(char *) message);
adefer_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
message->verp_delims,
qmgr_active_done_3_defer_flush,
adefer_warn(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_3_defer_warn,
(char *) message);
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt,
#include <opened.h>
#include <resolve_local.h>
#include <verp_sender.h>
+#include <mail_proto.h>
/* Client stubs. */
message->data_offset = 0;
message->queue_id = mystrdup(queue_id);
message->queue_name = mystrdup(queue_name);
+ message->encoding = 0;
message->sender = 0;
message->errors_to = 0;
message->return_receipt = 0;
long save_offset = message->rcpt_offset; /* save a flag */
char *start;
int recipient_limit;
+ const char *error_text;
+ char *name;
+ char *value;
/*
* Initialize. No early returns or we have a memory leak.
break;
}
}
+ } else if (rec_type == REC_TYPE_ATTR) {
+ if ((error_text = split_nameval(start, &name, &value)) != 0) {
+ msg_warn("%s: bad attribute: %s: %.200s",
+ message->queue_id, error_text, start);
+ break;
+ }
+ if (strcmp(name, MAIL_ATTR_ENCODING) == 0)
+ if (message->encoding == 0)
+ message->encoding = mystrdup(value);
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0) {
message->errors_to = mystrdup(start);
message->errors_to = mystrdup("");
if (message->return_receipt == 0)
message->return_receipt = mystrdup("");
+ if (message->encoding == 0)
+ message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
/*
* Clean up.
qmgr_job_free(job);
myfree(message->queue_id);
myfree(message->queue_name);
+ if (message->encoding)
+ myfree(message->encoding);
if (message->sender)
myfree(message->sender);
if (message->verp_delims)
pickup.o: ../../include/vstream.h
pickup.o: ../../include/set_ugid.h
pickup.o: ../../include/safe_open.h
+pickup.o: ../../include/stringops.h
pickup.o: ../../include/mail_queue.h
pickup.o: ../../include/mail_open_ok.h
pickup.o: ../../include/mymalloc.h
#include <vstream.h>
#include <set_ugid.h>
#include <safe_open.h>
+#include <stringops.h>
/* Global library. */
{
int type;
int check_first = (*expected == REC_TYPE_CONTENT[0]);
+ const char *error_text;
+ char *attr_name;
+ char *attr_value;
/*
* Limit the input record size. All front-end programs should protect the
* mail system against unreasonable inputs. This also requires that we
* limit the size of envelope records written by the local posting agent.
+ *
* As time stamp we use the scrutinized queue file modification time, and
* ignore the time stamp embedded in the queue file.
+ *
+ * Allow attribute records if the queue file is owned by the mail system
+ * (postsuper -r) or if the attribute specifies the MIME body type
+ * (sendmail -B).
*/
for (;;) {
if ((type = rec_get(qfile, buf, var_line_limit)) < 0
info->rcpt = mystrdup(vstring_str(buf));
if (type == REC_TYPE_TIME)
continue;
+ if (type == REC_TYPE_ATTR) {
+ if ((error_text = split_nameval(vstring_str(buf), &attr_name,
+ &attr_value)) != 0) {
+ msg_warn("uid=%ld: malformed attribute record: %s: %.200s",
+ (long) info->st.st_uid, error_text, vstring_str(buf));
+ continue;
+ }
+#define STREQ(x,y) (strcmp(x,y) == 0)
+
+ if (info->st.st_uid == var_owner_uid
+ || (STREQ(attr_name, MAIL_ATTR_ENCODING)
+ && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
+ || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
+ || STREQ(attr_value, MAIL_ATTR_ENC_NONE)))) {
+ rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
+ attr_name, attr_value);
+ continue;
+ }
+ msg_warn("uid=%ld: ignoring attribute record: %.200s=%.200s",
+ (long) info->st.st_uid, attr_name, attr_value);
+ continue;
+ }
if (type == REC_TYPE_FILT && *expected == REC_TYPE_ENVELOPE[0])
continue;
else {
if (*var_filter_xport)
rec_fprintf(cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
+ /*
+ * Origin is local.
+ */
+ rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ORIGIN, MAIL_ATTR_ORG_LOCAL);
+
/*
* Copy the message envelope segment. Allow only those records that we
* expect to see in the envelope section. The envelope segment must
int status;
VSTREAM *qfile;
VSTREAM *cleanup;
- int fd;
/*
* Open the submitted file. If we cannot open it, and we're not having a
* Perhaps we should save "bad" files elsewhere for further inspection.
* XXX How can we delete a file when open() fails with ENOENT?
*/
- qfile = safe_open(info->path, O_RDONLY | O_NONBLOCK, 0,
- (struct stat *) 0, -1, -1, buf);
+ qfile = safe_open(info->path, O_RDONLY | O_NONBLOCK, 0,
+ (struct stat *) 0, -1, -1, buf);
if (qfile == 0) {
if (errno != ENOENT)
msg_warn("open input file %s: %s", info->path, vstring_str(buf));
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/resolve_local.h
qmgr_message.o: ../../include/verp_sender.h
+qmgr_message.o: ../../include/mail_proto.h
+qmgr_message.o: ../../include/iostuff.h
+qmgr_message.o: ../../include/attr.h
qmgr_message.o: ../../include/resolve_clnt.h
qmgr_message.o: qmgr.h
qmgr_message.o: ../../include/scan_dir.h
long data_offset; /* data seek offset */
char *queue_name; /* queue name */
char *queue_id; /* queue file */
+ char *encoding; /* content encoding */
char *sender; /* complete address */
char *verp_delims; /* VERP delimiters */
char *errors_to; /* error report address */
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_2_bounce_flush,
(char *) message);
abounce_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
message->verp_delims,
qmgr_active_done_2_bounce_flush,
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_3_defer_flush,
(char *) message);
adefer_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
message->verp_delims,
qmgr_active_done_3_defer_flush,
adefer_warn(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
+ message->encoding,
message->errors_to,
qmgr_active_done_3_defer_warn,
(char *) message);
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt,
#include <opened.h>
#include <resolve_local.h>
#include <verp_sender.h>
+#include <mail_proto.h>
/* Client stubs. */
message->data_offset = 0;
message->queue_id = mystrdup(queue_id);
message->queue_name = mystrdup(queue_name);
+ message->encoding = 0;
message->sender = 0;
message->errors_to = 0;
message->return_receipt = 0;
char *start;
struct stat st;
int nrcpt = 0;
+ const char *error_text;
+ char *name;
+ char *value;
/*
* Initialize. No early returns or we have a memory leak.
}
if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
+ } else if (rec_type == REC_TYPE_ATTR) {
+ if ((error_text = split_nameval(start, &name, &value)) != 0) {
+ msg_warn("%s: bad attribute: %s: %.200s",
+ message->queue_id, error_text, start);
+ break;
+ }
+ if (strcmp(name, MAIL_ATTR_ENCODING) == 0)
+ if (message->encoding == 0)
+ message->encoding = mystrdup(value);
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0)
message->errors_to = mystrdup(start);
message->errors_to = mystrdup("");
if (message->return_receipt == 0)
message->return_receipt = mystrdup("");
+ if (message->encoding == 0)
+ message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
/*
* Clean up.
msg_panic("qmgr_message_free: queue file is open");
myfree(message->queue_id);
myfree(message->queue_name);
+ if (message->encoding)
+ myfree(message->encoding);
if (message->sender)
myfree(message->sender);
if (message->verp_delims)
state->sender = mystrndup(STR(state->buf), LEN(state->buf));
}
+/* qmqpd_write_attributes - save session attributes */
+
+static void qmqpd_write_attributes(QMQPD_STATE *state)
+{
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_CLIENT_NAME, state->name);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_CLIENT_ADDR, state->addr);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ORIGIN, state->namaddr);
+}
+
/* qmqpd_copy_recipients - copy message recipients */
static void qmqpd_copy_recipients(QMQPD_STATE *state)
*/
qmqpd_copy_sender(state);
+ /*
+ * Record some session attributes.
+ */
+ qmqpd_write_attributes(state);
+
/*
* Read and write the envelope recipients, including the optional big
* brother recipient.
/* controlled by parameters in the \fBmain.cf\fR configuration file.
/*
/* The following options are recognized:
-/* .IP "\fB-B \fIbody_type\fR (ignored)"
-/* The message body MIME type. Currently, Postfix implements
-/* \fBjust-send-eight\fR.
+/* .IP "\fB-B \fIbody_type\fR"
+/* The message body MIME type: \fB7BIT\fR or \fB8BITMIME\fR.
/* .IP "\fB-C \fIconfig_file\fR (ignored :-)"
/* The path name of the \fBsendmail.cf\fR file. Postfix configuration
/* files are kept in \fB/etc/postfix\fR.
/* enqueue - post one message */
-static void enqueue(const int flags, const char *sender, const char *full_name,
- char **recipients)
+static void enqueue(const int flags, const char *encoding, const char *sender,
+ const char *full_name, char **recipients)
{
VSTRING *buf;
VSTREAM *dst;
rec_fputs(dst, REC_TYPE_FROM, saved_sender);
if (verp_delims && *saved_sender == 0)
msg_fatal("-V option requires non-null sender address");
+ if (encoding)
+ rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding);
if (verp_delims)
rec_fputs(dst, REC_TYPE_VERP, verp_delims);
if (recipients) {
int n;
int flags = SM_FLAG_DEFAULT;
char *site_to_flush = 0;
+ char *encoding = 0;
/*
* Be consistent with file permissions.
break;
case 'n':
msg_fatal_status(EX_USAGE, "-%c option not supported", c);
+ case 'B':
+ if (strcmp(optarg, "8BITMIME") == 0)/* RFC 1652 */
+ encoding = MAIL_ATTR_ENC_8BIT;
+ else if (strcmp(optarg, "7BIT") == 0) /* RFC 1652 */
+ encoding = MAIL_ATTR_ENC_7BIT;
+ else
+ msg_fatal_status(EX_USAGE, "-B option needs 8BITMIME or 7BIT");
+ break;
case 'F': /* full name */
full_name = optarg;
break;
/* NOTREACHED */
case SM_MODE_ENQUEUE:
if (site_to_flush == 0) {
- enqueue(flags, sender, full_name, argv + OPTIND);
+ enqueue(flags, encoding, sender, full_name, argv + OPTIND);
exit(0);
}
if (argv[OPTIND])
smtp_proto.o: ../../include/mark_corrupt.h
smtp_proto.o: ../../include/quote_821_local.h
smtp_proto.o: ../../include/quote_flags.h
+smtp_proto.o: ../../include/mail_proto.h
+smtp_proto.o: ../../include/attr.h
smtp_proto.o: smtp.h
smtp_proto.o: ../../include/argv.h
smtp_proto.o: smtp_sasl.h
/* STANDARDS
/* RFC 821 (SMTP protocol)
/* RFC 1651 (SMTP service extensions)
+/* RFC 1652 (8bit-MIME transport)
/* RFC 1870 (Message Size Declaration)
/* RFC 2197 (Pipelining)
/* RFC 2554 (AUTH command)
#include <off_cvt.h>
#include <mark_corrupt.h>
#include <quote_821_local.h>
+#include <mail_proto.h>
/* Application-specific. */
/*
* Macros for readability.
*/
-#define REWRITE_ADDRESS(addr) do { \
- if (*(addr)) { \
- quote_821_local(state->scratch, addr, QUOTE_FLAG_8BITCLEAN); \
- smtp_unalias_addr(state->scratch2, vstring_str(state->scratch)); \
- myfree(addr); \
- addr = mystrdup(vstring_str(state->scratch2)); \
+#define REWRITE_ADDRESS(dst, mid, src) do { \
+ if (*(src)) { \
+ quote_821_local(mid, src, QUOTE_FLAG_8BITCLEAN); \
+ smtp_unalias_addr(dst, vstring_str(mid)); \
+ } else { \
+ vstring_strcpy(dst, src); \
} \
} while (0)
-#define QUOTE_ADDRESS(addr) do { \
- if (*(addr)) { \
- quote_821_local(state->scratch, addr, QUOTE_FLAG_8BITCLEAN); \
- myfree(addr); \
- addr = mystrdup(vstring_str(state->scratch)); \
+#define QUOTE_ADDRESS(dst, src) do { \
+ if (*(src)) { \
+ quote_821_local(dst, src, QUOTE_FLAG_8BITCLEAN); \
+ } else { \
+ vstring_strcpy(dst, src); \
} \
} while (0)
*/
case SMTP_STATE_MAIL:
if (var_disable_dns == 0) {
- REWRITE_ADDRESS(request->sender);
+ REWRITE_ADDRESS(state->scratch, state->scratch2,
+ request->sender);
} else {
- QUOTE_ADDRESS(request->sender);
+ QUOTE_ADDRESS(state->scratch, request->sender);
}
- vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
- if (state->features & SMTP_FEATURE_SIZE)
+ vstring_sprintf(next_command, "MAIL FROM:<%s>",
+ vstring_str(state->scratch));
+ if (state->features & SMTP_FEATURE_SIZE) /* RFC 1652 */
vstring_sprintf_append(next_command, " SIZE=%lu",
request->data_size);
+ if (state->features & SMTP_FEATURE_8BITMIME) {
+ if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
+ vstring_strcat(next_command, " BODY=8BITMIME");
+ else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
+ vstring_strcat(next_command, " BODY=7BIT");
+ else if (strcmp(request->encoding, MAIL_ATTR_ENC_NONE) != 0)
+ msg_warn("%s: unknown content encoding: %s",
+ request->queue_id, request->encoding);
+ }
next_state = SMTP_STATE_RCPT;
break;
case SMTP_STATE_RCPT:
rcpt = request->rcpt_list.info + send_rcpt;
if (var_disable_dns == 0) {
- REWRITE_ADDRESS(rcpt->address);
+ REWRITE_ADDRESS(state->scratch, state->scratch2,
+ rcpt->address);
} else {
- QUOTE_ADDRESS(rcpt->address);
+ QUOTE_ADDRESS(state->scratch, rcpt->address);
}
- vstring_sprintf(next_command, "RCPT TO:<%s>", rcpt->address);
+ vstring_sprintf(next_command, "RCPT TO:<%s>",
+ vstring_str(state->scratch));
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
next_state = SMTP_STATE_DATA;
break;
smtpd.o: ../../include/string_list.h
smtpd.o: ../../include/match_list.h
smtpd.o: ../../include/match_ops.h
+smtpd.o: ../../include/quote_822_local.h
+smtpd.o: ../../include/quote_flags.h
smtpd.o: ../../include/mail_server.h
smtpd.o: smtpd_token.h
smtpd.o: smtpd.h
int narg;
char *arg;
char *verp_delims = 0;
+ char *encoding = 0;
state->msg_size = 0;
}
for (narg = 3; narg < argc; narg++) {
arg = argv[narg].strval;
- if (strcasecmp(arg, "BODY=8BITMIME") == 0
- || strcasecmp(arg, "BODY=7BIT") == 0) {
- /* void */ ;
- } else if (strncasecmp(arg, "SIZE=", 5) == 0) {
+ if (strcasecmp(arg, "BODY=8BITMIME") == 0) { /* RFC 1652 */
+ encoding = MAIL_ATTR_ENC_8BIT;
+ } else if (strcasecmp(arg, "BODY=7BIT") == 0) { /* RFC 1652 */
+ encoding = MAIL_ATTR_ENC_7BIT;
+ } else if (strncasecmp(arg, "SIZE=", 5) == 0) { /* RFC 1870 */
/* Reject non-numeric size. */
if (!alldig(arg + 5)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
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 (encoding != 0)
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ENCODING, encoding);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_CLIENT_NAME, state->name);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_CLIENT_ADDR, state->addr);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_ORIGIN, state->namaddr);
+ if (state->helo_name != 0)
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_HELO_NAME, state->helo_name);
if (verp_delims)
rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
state->sender = mystrdup(argv[2].strval);
unix_connect.c unix_listen.c unix_trigger.c unsafe.c username.c \
valid_hostname.c vbuf.c vbuf_print.c vstream.c vstream_popen.c \
vstring.c vstring_vstream.c watchdog.c writable.c write_buf.c \
- write_wait.c strcasecmp.c
+ write_wait.c strcasecmp.c nvtable.c
OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
unix_connect.o unix_listen.o unix_trigger.o unsafe.o username.o \
valid_hostname.o vbuf.o vbuf_print.o vstream.o vstream_popen.o \
vstring.o vstring_vstream.o watchdog.o writable.o write_buf.o \
- write_wait.o $(STRCASE)
+ write_wait.o nvtable.o $(STRCASE)
HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
scan_dir.h set_eugid.h set_ugid.h sigdelay.h spawn_command.h \
split_at.h stat_as.h stringops.h sys_defs.h timed_connect.h \
timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \
- vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h
+ vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \
+ nvtable.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
non_blocking.o: sys_defs.h
non_blocking.o: msg.h
non_blocking.o: iostuff.h
+nvtable.o: nvtable.c
+nvtable.o: sys_defs.h
+nvtable.o: mymalloc.h
+nvtable.o: htable.h
+nvtable.o: nvtable.h
open_as.o: open_as.c
open_as.o: sys_defs.h
open_as.o: msg.h
char *myname = "dict_eval_action";
const char *pp;
- if (msg_verbose)
+ if (msg_verbose > 1)
msg_info("%s: type %s buf %s context %s \"%s\" %s",
myname, type == MAC_PARSE_VARNAME ? "variable" : "literal",
STR(buf), ctxt->dict_name, STR(ctxt->buf),
--- /dev/null
+/*++
+/* NAME
+/* nvtable 3
+/* SUMMARY
+/* attribute list manager
+/* SYNOPSIS
+/* #include <nvtable.h>
+/*
+/* typedef struct {
+/* .in +4
+/* char *key;
+/* char *value;
+/* /* private fields... */
+/* .in -4
+/* } NVTABLE_INFO;
+/*
+/* NVTABLE *nvtable_create(size)
+/* int size;
+/*
+/* NVTABLE_INFO *nvtable_update(table, key, value)
+/* NVTABLE *table;
+/* const char *key;
+/* const char *value;
+/*
+/* char *nvtable_find(table, key)
+/* NVTABLE *table;
+/* const char *key;
+/*
+/* NVTABLE_INFO *nvtable_locate(table, key)
+/* NVTABLE *table;
+/* const char *key;
+/*
+/* void nvtable_delete(table, key)
+/* NVTABLE *table;
+/* const char *key;
+/*
+/* void nvtable_free(table)
+/* NVTABLE *table;
+/*
+/* void nvtable_walk(table, action, ptr)
+/* NVTABLE *table;
+/* void (*action)(NVTABLE_INFO *, char *ptr);
+/* char *ptr;
+/*
+/* NVTABLE_INFO **nvtable_list(table)
+/* NVTABLE *table;
+/* DESCRIPTION
+/* This module maintains one or more attribute lists. It provides a
+/* more convenient interface than hash tables, although it uses the
+/* same underlying implementation. Each attribute list entry consists
+/* of a unique string-valued lookup key and a string value.
+/*
+/* nvtable_create() creates a table of the specified size and returns a
+/* pointer to the result.
+/*
+/* nvtable_update() stores or updates a (key, value) pair in the specified
+/* table and returns a pointer to the resulting entry. The key and the
+/* value are copied.
+/*
+/* nvtable_find() returns the value that was stored under the given key,
+/* or a null pointer if it was not found. In order to distinguish
+/* a null value from a non-existent value, use nvtable_locate().
+/*
+/* nvtable_locate() returns a pointer to the entry that was stored
+/* for the given key, or a null pointer if it was not found.
+/*
+/* nvtable_delete() removes one entry that was stored under the given key.
+/*
+/* nvtable_free() destroys a hash table, including contents.
+/*
+/* nvtable_walk() invokes the action function for each table entry, with
+/* a pointer to the entry as its argument. The ptr argument is passed
+/* on to the action function.
+/*
+/* nvtable_list() returns a null-terminated list of pointers to
+/* all elements in the named table. The list should be passed to
+/* myfree().
+/* RESTRICTIONS
+/* A callback function should not modify the attribute list that is
+/* specified to its caller.
+/* DIAGNOSTICS
+/* The following conditions are reported and cause the program to
+/* terminate immediately: memory allocation failure; an attempt
+/* to delete a non-existent entry.
+/* SEE ALSO
+/* mymalloc(3) memory management wrapper
+/* htable(3) hash table manager
+/* 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
+/*--*/
+
+/* C library */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <htable.h>
+#include <nvtable.h>
+
+/* nvtable_update - update or enter (key, value) pair */
+
+NVTABLE_INFO *nvtable_update(NVTABLE * table, const char *key, const char *value)
+{
+ NVTABLE_INFO *ht;
+
+ if ((ht = htable_locate(table, key)) != 0) {
+ myfree(ht->value);
+ } else {
+ ht = htable_enter(table, key, (char *) 0);
+ }
+ ht->value = mystrdup(value);
+ return (ht);
+}
--- /dev/null
+#ifndef _NVTABLE_H_INCLUDED_
+#define _NVTABLE_H_INCLUDED_
+
+/*++
+/* NAME
+/* nvtable 3h
+/* SUMMARY
+/* attribute list manager
+/* SYNOPSIS
+/* #include <nvtable.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <htable.h>
+#include <mymalloc.h>
+
+typedef struct HTABLE NVTABLE;
+typedef struct HTABLE_INFO NVTABLE_INFO;
+
+#define nvtable_create(size) htable_create(size)
+#define nvtable_locate(table, key) htable_locate((table), (key))
+#define nvtable_walk(table, action, ptr) htable_walk((table), (action), (ptr))
+#define nvtable_list(table) htable_list(table)
+#define nvtable_find(table, key) htable_find((table), (key))
+#define nvtable_delete(table, key) htable_delete((table), (key), myfree)
+#define nvtable_free(table) htable_free((table), myfree)
+
+extern NVTABLE_INFO *nvtable_update(NVTABLE *, 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