mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-28 20:57:56 +00:00
postfix-3.1-20151129
This commit is contained in:
parent
fd122dde8c
commit
6b8ab5dd1f
@ -22010,3 +22010,18 @@ Apologies for any names omitted.
|
||||
Bitrot: OpenSSL API cleanups. Viktor Dukhovni. Files:
|
||||
.indent.pro, tls/tls.h, tls/tls_dane.c, tls/tls_fprint.c,
|
||||
tls/tls_misc.c, tls/tls_server.c, tls/tls_verify.c.
|
||||
|
||||
20151124
|
||||
|
||||
Bugfix (introduced: Postfix 3.0): don't throttle a destination
|
||||
after opportunistic TLS failure. Viktor Dukhovni and Wietse.
|
||||
Files: smtp/smtp_proto.c, smtp/smtp.h, smtp/smtp_trouble.c.
|
||||
|
||||
20151128
|
||||
|
||||
Feature: JSON-formatted queue listing with "postqueue -j".
|
||||
Output is a stream of JSON objects, one per queue file. To
|
||||
simplify stream-mode parsing, each JSON object is followed by
|
||||
a newline character. Files: postqueue/postqueue.c,
|
||||
postqueue/postqueue.h, postqueue/showq_compat.c,
|
||||
postqueue/showq_json.c, showq/showq.c.
|
||||
|
@ -105,8 +105,8 @@ later.
|
||||
6 smtpd_starttls_timeout = ${stress?{10}:{300}}s
|
||||
7 address_verify_poll_count = ${stress?{1}:{3}}
|
||||
|
||||
With Postfix versions before 3.0, replace ${stress?{x}:{y}} with ${stress?x}$
|
||||
{stress:y}.
|
||||
Postfix versions before 3.0 use the older form ${stress?x}${stress:y} instead
|
||||
of the newer form ${stress?{x}:{y}}.
|
||||
|
||||
Translation:
|
||||
|
||||
@ -149,8 +149,8 @@ Translation:
|
||||
$unverified_sender_tempfail_action. No mail should be lost, as long as this
|
||||
measure is used only temporarily.
|
||||
|
||||
The syntax of ${name?value} and ${name:value} is explained at the beginning of
|
||||
the postconf(5) manual page.
|
||||
The syntax of ${name?{value}:{value}}, ${name?value} and ${name:value} is
|
||||
explained at the beginning of the postconf(5) manual page.
|
||||
|
||||
NOTE: Please keep in mind that the stress-adaptive feature is a fairly
|
||||
desperate measure to keep ssoommee legitimate mail flowing under overload
|
||||
|
@ -168,8 +168,8 @@ default with Postfix 2.6 and later. </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> With Postfix versions before 3.0, replace ${stress?{x}:{y}}
|
||||
with ${stress?x}${stress:y}. </p>
|
||||
<p> Postfix versions before 3.0 use the older form ${stress?x}${stress:y}
|
||||
instead of the newer form ${stress?{x}:{y}}. </p>
|
||||
|
||||
<p> Translation: <p>
|
||||
|
||||
@ -219,8 +219,9 @@ as this measure is used only temporarily. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> The syntax of ${name?value} and ${name:value} is explained at
|
||||
the beginning of the <a href="postconf.5.html">postconf(5)</a> manual page. </p>
|
||||
<p> The syntax of ${name?{value}:{value}}, ${name?value} and
|
||||
${name:value} is explained at the beginning of the <a href="postconf.5.html">postconf(5)</a>
|
||||
manual page. </p>
|
||||
|
||||
<p> NOTE: Please keep in mind that the stress-adaptive feature is
|
||||
a fairly desperate measure to keep <b>some</b> legitimate mail
|
||||
|
@ -10,11 +10,20 @@ POSTQUEUE(1) POSTQUEUE(1)
|
||||
postqueue - Postfix queue control
|
||||
|
||||
<b>SYNOPSIS</b>
|
||||
<b>To flush the mail queue</b>:
|
||||
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-f</b>
|
||||
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-i</b> <i>queue</i><b>_</b><i>id</i>
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-p</b>
|
||||
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-s</b> <i>site</i>
|
||||
|
||||
<b>To list the mail queue</b>:
|
||||
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-j</b>
|
||||
|
||||
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-p</b>
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
The <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command implements the Postfix user interface for
|
||||
queue management. It implements operations that are traditionally
|
||||
@ -46,6 +55,51 @@ POSTQUEUE(1) POSTQUEUE(1)
|
||||
|
||||
This feature is available with Postfix version 2.4 and later.
|
||||
|
||||
<b>-j</b> Produce a queue listing in JSON format, based on output from the
|
||||
<a href="showq.8.html">showq(8)</a> daemon. The result is a stream of zero or more JSON
|
||||
objects, one per queue file. Each object is followed by a new-
|
||||
line character to support simple streaming parsers.
|
||||
|
||||
Object members have string values unless indicated otherwise.
|
||||
Programs should ignore object members that are not listed here;
|
||||
the list of members is expected to grow over time.
|
||||
|
||||
<b>queue_name</b>
|
||||
The name of the queue where the message was found. Note
|
||||
that the contents of the mail queue may change while it
|
||||
is being listed; some messages may appear more than once,
|
||||
and some messages may be missed.
|
||||
|
||||
<b>queue_id</b>
|
||||
The queue file name. The name may be reused unless
|
||||
"<a href="postconf.5.html#enable_long_queue_ids">enable_long_queue_ids</a> = true".
|
||||
|
||||
<b>arrival_time</b>
|
||||
The number of seconds since the start of the UNIX epoch.
|
||||
|
||||
<b>message_size</b>
|
||||
The number of bytes in the message header and body. This
|
||||
number does not include message envelope information. It
|
||||
is approximately equal to the number of bytes that would
|
||||
be transmitted via SMTP including the <CR><LF> line end-
|
||||
ings.
|
||||
|
||||
<b>sender</b> The envelope sender address.
|
||||
|
||||
<b>recipients</b>
|
||||
An array containing zero or more objects with members:
|
||||
|
||||
<b>address</b>
|
||||
One recipient address.
|
||||
|
||||
<b>delay_reason</b>
|
||||
If present, the reason for delayed delivery. Some
|
||||
delayed recipients have no delay reason, for exam-
|
||||
ple, when delivery is in progress or when the sys-
|
||||
tem was stopped before it could record the reason.
|
||||
|
||||
This feature is available in Postfix 3.1 and later.
|
||||
|
||||
<b>-p</b> Produce a traditional sendmail-style queue listing. This option
|
||||
implements the traditional <b>mailq</b> command, by contacting the
|
||||
Postfix <a href="showq.8.html"><b>showq</b>(8)</a> daemon.
|
||||
@ -82,6 +136,9 @@ POSTQUEUE(1) POSTQUEUE(1)
|
||||
This program is designed to run with set-group ID privileges, so that
|
||||
it can connect to Postfix daemon processes.
|
||||
|
||||
<b>STANDARDS</b>
|
||||
<a href="http://tools.ietf.org/html/rfc7159">RFC 7159</a> (JSON notation)
|
||||
|
||||
<b>DIAGNOSTICS</b>
|
||||
Problems are logged to <b>syslogd</b>(8) and to the standard error stream.
|
||||
|
||||
@ -169,5 +226,10 @@ POSTQUEUE(1) POSTQUEUE(1)
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
Wietse Venema
|
||||
Google, Inc.
|
||||
111 8th Avenue
|
||||
New York, NY 10011, USA
|
||||
|
||||
POSTQUEUE(1)
|
||||
</pre> </body> </html>
|
||||
|
@ -13,17 +13,18 @@ SHOWQ(8) SHOWQ(8)
|
||||
<b>showq</b> [generic Postfix daemon options]
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon reports the Postfix mail queue status. It is the
|
||||
program that emulates the sendmail `mailq' command.
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon reports the Postfix mail queue status. The output
|
||||
is meant to be formatted by the <a href="postqueue.1.html">postqueue(1)</a> command, as it emulates
|
||||
the Sendmail `mailq' command.
|
||||
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon can also be run in stand-alone mode by the supe-
|
||||
ruser. This mode of operation is used to emulate the `mailq' command
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon can also be run in stand-alone mode by the supe-
|
||||
ruser. This mode of operation is used to emulate the `mailq' command
|
||||
while the Postfix mail system is down.
|
||||
|
||||
<b>SECURITY</b>
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon can run in a chroot jail at fixed low privilege,
|
||||
and takes no input from the client. Its service port is accessible to
|
||||
local untrusted users, so the service can be susceptible to denial of
|
||||
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon can run in a chroot jail at fixed low privilege,
|
||||
and takes no input from the client. Its service port is accessible to
|
||||
local untrusted users, so the service can be susceptible to denial of
|
||||
service attacks.
|
||||
|
||||
<b>STANDARDS</b>
|
||||
@ -33,19 +34,19 @@ SHOWQ(8) SHOWQ(8)
|
||||
Problems and transactions are logged to <b>syslogd</b>(8).
|
||||
|
||||
<b>CONFIGURATION PARAMETERS</b>
|
||||
Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="showq.8.html"><b>showq</b>(8)</a> processes
|
||||
Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="showq.8.html"><b>showq</b>(8)</a> processes
|
||||
run for only a limited amount of time. Use the command "<b>postfix reload</b>"
|
||||
to speed up a change.
|
||||
|
||||
The text below provides only a parameter summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for
|
||||
The text below provides only a parameter summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for
|
||||
more details including examples.
|
||||
|
||||
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
figuration files.
|
||||
|
||||
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
request before it is terminated by a built-in watchdog timer.
|
||||
|
||||
<b><a href="postconf.5.html#duplicate_filter_limit">duplicate_filter_limit</a> (1000)</b>
|
||||
@ -57,11 +58,11 @@ SHOWQ(8) SHOWQ(8)
|
||||
The recipient of mail addressed to the null address.
|
||||
|
||||
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
|
||||
The time limit for sending or receiving information over an
|
||||
The time limit for sending or receiving information over an
|
||||
internal communication channel.
|
||||
|
||||
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
waits for an incoming connection before terminating voluntarily.
|
||||
|
||||
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
|
||||
@ -81,8 +82,8 @@ SHOWQ(8) SHOWQ(8)
|
||||
The syslog facility of Postfix logging.
|
||||
|
||||
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
|
||||
The mail system name that is prepended to the process name in
|
||||
syslog records, so that "smtpd" becomes, for example, "post-
|
||||
The mail system name that is prepended to the process name in
|
||||
syslog records, so that "smtpd" becomes, for example, "post-
|
||||
fix/smtpd".
|
||||
|
||||
Available in Postfix version 2.9 and later:
|
||||
@ -110,5 +111,10 @@ SHOWQ(8) SHOWQ(8)
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
Wietse Venema
|
||||
Google, Inc.
|
||||
111 8th Avenue
|
||||
New York, NY 10011, USA
|
||||
|
||||
SHOWQ(8)
|
||||
</pre> </body> </html>
|
||||
|
@ -158,6 +158,11 @@
|
||||
# IBM T.J. Watson Research
|
||||
# P.O. Box 704
|
||||
# Yorktown Heights, NY 10598, USA
|
||||
#
|
||||
# Wietse Venema
|
||||
# Google, Inc.
|
||||
# 111 8th Avenue
|
||||
# New York, NY 10011, USA
|
||||
#--
|
||||
|
||||
# Emit system-dependent Makefile macro definitions to standard output.
|
||||
|
@ -8,13 +8,19 @@ Postfix queue control
|
||||
.SH "SYNOPSIS"
|
||||
.na
|
||||
.nf
|
||||
\fBTo flush the mail queue\fR:
|
||||
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-f\fR
|
||||
.br
|
||||
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-i \fIqueue_id\fR
|
||||
.br
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-p\fR
|
||||
.br
|
||||
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-s \fIsite\fR
|
||||
|
||||
\fBTo list the mail queue\fR:
|
||||
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-j\fR
|
||||
|
||||
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-p\fR
|
||||
.SH DESCRIPTION
|
||||
.ad
|
||||
.fi
|
||||
@ -46,6 +52,48 @@ This option implements the traditional \fBsendmail \-qI\fR
|
||||
command, by contacting the \fBflush\fR(8) server.
|
||||
|
||||
This feature is available with Postfix version 2.4 and later.
|
||||
.IP "\fB\-j\fR"
|
||||
Produce a queue listing in JSON format, based on output
|
||||
from the showq(8) daemon. The result is a stream of zero
|
||||
or more JSON objects, one per queue file. Each object is
|
||||
followed by a newline character to support simple streaming
|
||||
parsers.
|
||||
.sp
|
||||
Object members have string values unless indicated otherwise.
|
||||
Programs should ignore object members that are not listed
|
||||
here; the list of members is expected to grow over time.
|
||||
.RS
|
||||
.IP \fBqueue_name\fB
|
||||
The name of the queue where the message was found. Note
|
||||
that the contents of the mail queue may change while it is
|
||||
being listed; some messages may appear more than once, and
|
||||
some messages may be missed.
|
||||
.IP \fBqueue_id\fB
|
||||
The queue file name. The name may be reused unless
|
||||
"enable_long_queue_ids = true".
|
||||
.IP \fBarrival_time\fB
|
||||
The number of seconds since the start of the UNIX epoch.
|
||||
.IP \fBmessage_size\fB
|
||||
The number of bytes in the message header and body. This
|
||||
number does not include message envelope information. It
|
||||
is approximately equal to the number of bytes that would
|
||||
be transmitted via SMTP including the <CR><LF> line endings.
|
||||
.IP \fBsender\fB
|
||||
The envelope sender address.
|
||||
.IP \fBrecipients\fB
|
||||
An array containing zero or more objects with members:
|
||||
.RS
|
||||
.IP \fBaddress\fB
|
||||
One recipient address.
|
||||
.IP \fBdelay_reason\fB
|
||||
If present, the reason for delayed delivery. Some delayed
|
||||
recipients have no delay reason, for example, when delivery
|
||||
is in progress or when the system was stopped before it
|
||||
could record the reason.
|
||||
.RE
|
||||
.RE
|
||||
.IP
|
||||
This feature is available in Postfix 3.1 and later.
|
||||
.IP \fB\-p\fR
|
||||
Produce a traditional sendmail\-style queue listing.
|
||||
This option implements the traditional \fBmailq\fR command,
|
||||
@ -85,6 +133,10 @@ this option is available for the super\-user only.
|
||||
.fi
|
||||
This program is designed to run with set\-group ID privileges, so
|
||||
that it can connect to Postfix daemon processes.
|
||||
.SH "STANDARDS"
|
||||
.na
|
||||
.nf
|
||||
RFC 7159 (JSON notation)
|
||||
.SH DIAGNOSTICS
|
||||
.ad
|
||||
.fi
|
||||
@ -187,3 +239,8 @@ Wietse Venema
|
||||
IBM T.J. Watson Research
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
Wietse Venema
|
||||
Google, Inc.
|
||||
111 8th Avenue
|
||||
New York, NY 10011, USA
|
||||
|
@ -13,7 +13,8 @@ list the Postfix mail queue
|
||||
.ad
|
||||
.fi
|
||||
The \fBshowq\fR(8) daemon reports the Postfix mail queue status.
|
||||
It is the program that emulates the sendmail `mailq' command.
|
||||
The output is meant to be formatted by the postqueue(1) command,
|
||||
as it emulates the Sendmail `mailq' command.
|
||||
|
||||
The \fBshowq\fR(8) daemon can also be run in stand\-alone mode
|
||||
by the superuser. This mode of operation is used to emulate
|
||||
@ -111,3 +112,8 @@ Wietse Venema
|
||||
IBM T.J. Watson Research
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
Wietse Venema
|
||||
Google, Inc.
|
||||
111 8th Avenue
|
||||
New York, NY 10011, USA
|
||||
|
@ -183,6 +183,11 @@
|
||||
# IBM T.J. Watson Research
|
||||
# P.O. Box 704
|
||||
# Yorktown Heights, NY 10598, USA
|
||||
#
|
||||
# Wietse Venema
|
||||
# Google, Inc.
|
||||
# 111 8th Avenue
|
||||
# New York, NY 10011, USA
|
||||
#--
|
||||
|
||||
# Initialize.
|
||||
|
@ -168,8 +168,8 @@ default with Postfix 2.6 and later. </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> With Postfix versions before 3.0, replace ${stress?{x}:{y}}
|
||||
with ${stress?x}${stress:y}. </p>
|
||||
<p> Postfix versions before 3.0 use the older form ${stress?x}${stress:y}
|
||||
instead of the newer form ${stress?{x}:{y}}. </p>
|
||||
|
||||
<p> Translation: <p>
|
||||
|
||||
@ -219,8 +219,9 @@ as this measure is used only temporarily. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> The syntax of ${name?value} and ${name:value} is explained at
|
||||
the beginning of the postconf(5) manual page. </p>
|
||||
<p> The syntax of ${name?{value}:{value}}, ${name?value} and
|
||||
${name:value} is explained at the beginning of the postconf(5)
|
||||
manual page. </p>
|
||||
|
||||
<p> NOTE: Please keep in mind that the stress-adaptive feature is
|
||||
a fairly desperate measure to keep <b>some</b> legitimate mail
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20151031"
|
||||
#define MAIL_RELEASE_DATE "20151129"
|
||||
#define MAIL_VERSION_NUMBER "3.1"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -1,7 +1,7 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = postqueue.c
|
||||
OBJS = postqueue.o
|
||||
HDRS =
|
||||
SRCS = postqueue.c showq_compat.c showq_json.c
|
||||
OBJS = postqueue.o showq_compat.o showq_json.o
|
||||
HDRS = postqueue.h
|
||||
TESTSRC =
|
||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||
@ -16,7 +16,7 @@ LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
|
||||
$(PROG): $(OBJS) $(LIBS)
|
||||
$(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
|
||||
|
||||
$(OBJS): ../../conf/makedefs.out
|
||||
$(OBJS): ../../conf/makedefs.out postqueue.h
|
||||
|
||||
Makefile: Makefile.in
|
||||
cat ../../conf/makedefs.out $? >$@
|
||||
@ -84,6 +84,7 @@ postqueue.o: ../../include/mymalloc.h
|
||||
postqueue.o: ../../include/nvtable.h
|
||||
postqueue.o: ../../include/safe.h
|
||||
postqueue.o: ../../include/smtp_stream.h
|
||||
postqueue.o: ../../include/stringops.h
|
||||
postqueue.o: ../../include/sys_defs.h
|
||||
postqueue.o: ../../include/user_acl.h
|
||||
postqueue.o: ../../include/valid_hostname.h
|
||||
@ -93,3 +94,40 @@ postqueue.o: ../../include/vstream.h
|
||||
postqueue.o: ../../include/vstring.h
|
||||
postqueue.o: ../../include/warn_stat.h
|
||||
postqueue.o: postqueue.c
|
||||
postqueue.o: postqueue.h
|
||||
showq_compat.o: ../../include/attr.h
|
||||
showq_compat.o: ../../include/check_arg.h
|
||||
showq_compat.o: ../../include/htable.h
|
||||
showq_compat.o: ../../include/iostuff.h
|
||||
showq_compat.o: ../../include/mail_date.h
|
||||
showq_compat.o: ../../include/mail_params.h
|
||||
showq_compat.o: ../../include/mail_proto.h
|
||||
showq_compat.o: ../../include/mail_queue.h
|
||||
showq_compat.o: ../../include/msg.h
|
||||
showq_compat.o: ../../include/mymalloc.h
|
||||
showq_compat.o: ../../include/nvtable.h
|
||||
showq_compat.o: ../../include/stringops.h
|
||||
showq_compat.o: ../../include/sys_defs.h
|
||||
showq_compat.o: ../../include/vbuf.h
|
||||
showq_compat.o: ../../include/vstream.h
|
||||
showq_compat.o: ../../include/vstring.h
|
||||
showq_compat.o: postqueue.h
|
||||
showq_compat.o: showq_compat.c
|
||||
showq_json.o: ../../include/attr.h
|
||||
showq_json.o: ../../include/check_arg.h
|
||||
showq_json.o: ../../include/htable.h
|
||||
showq_json.o: ../../include/iostuff.h
|
||||
showq_json.o: ../../include/mail_date.h
|
||||
showq_json.o: ../../include/mail_params.h
|
||||
showq_json.o: ../../include/mail_proto.h
|
||||
showq_json.o: ../../include/mail_queue.h
|
||||
showq_json.o: ../../include/msg.h
|
||||
showq_json.o: ../../include/mymalloc.h
|
||||
showq_json.o: ../../include/nvtable.h
|
||||
showq_json.o: ../../include/stringops.h
|
||||
showq_json.o: ../../include/sys_defs.h
|
||||
showq_json.o: ../../include/vbuf.h
|
||||
showq_json.o: ../../include/vstream.h
|
||||
showq_json.o: ../../include/vstring.h
|
||||
showq_json.o: postqueue.h
|
||||
showq_json.o: showq_json.c
|
||||
|
@ -4,13 +4,19 @@
|
||||
/* SUMMARY
|
||||
/* Postfix queue control
|
||||
/* SYNOPSIS
|
||||
/* \fBTo flush the mail queue\fR:
|
||||
/*
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-f\fR
|
||||
/* .br
|
||||
/*
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-i \fIqueue_id\fR
|
||||
/* .br
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-p\fR
|
||||
/* .br
|
||||
/*
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-s \fIsite\fR
|
||||
/*
|
||||
/* \fBTo list the mail queue\fR:
|
||||
/*
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-j\fR
|
||||
/*
|
||||
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-p\fR
|
||||
/* DESCRIPTION
|
||||
/* The \fBpostqueue\fR(1) command implements the Postfix user interface
|
||||
/* for queue management. It implements operations that are
|
||||
@ -40,6 +46,48 @@
|
||||
/* command, by contacting the \fBflush\fR(8) server.
|
||||
/*
|
||||
/* This feature is available with Postfix version 2.4 and later.
|
||||
/* .IP "\fB-j\fR"
|
||||
/* Produce a queue listing in JSON format, based on output
|
||||
/* from the showq(8) daemon. The result is a stream of zero
|
||||
/* or more JSON objects, one per queue file. Each object is
|
||||
/* followed by a newline character to support simple streaming
|
||||
/* parsers.
|
||||
/* .sp
|
||||
/* Object members have string values unless indicated otherwise.
|
||||
/* Programs should ignore object members that are not listed
|
||||
/* here; the list of members is expected to grow over time.
|
||||
/* .RS
|
||||
/* .IP \fBqueue_name\fB
|
||||
/* The name of the queue where the message was found. Note
|
||||
/* that the contents of the mail queue may change while it is
|
||||
/* being listed; some messages may appear more than once, and
|
||||
/* some messages may be missed.
|
||||
/* .IP \fBqueue_id\fB
|
||||
/* The queue file name. The name may be reused unless
|
||||
/* "enable_long_queue_ids = true".
|
||||
/* .IP \fBarrival_time\fB
|
||||
/* The number of seconds since the start of the UNIX epoch.
|
||||
/* .IP \fBmessage_size\fB
|
||||
/* The number of bytes in the message header and body. This
|
||||
/* number does not include message envelope information. It
|
||||
/* is approximately equal to the number of bytes that would
|
||||
/* be transmitted via SMTP including the <CR><LF> line endings.
|
||||
/* .IP \fBsender\fB
|
||||
/* The envelope sender address.
|
||||
/* .IP \fBrecipients\fB
|
||||
/* An array containing zero or more objects with members:
|
||||
/* .RS
|
||||
/* .IP \fBaddress\fB
|
||||
/* One recipient address.
|
||||
/* .IP \fBdelay_reason\fB
|
||||
/* If present, the reason for delayed delivery. Some delayed
|
||||
/* recipients have no delay reason, for example, when delivery
|
||||
/* is in progress or when the system was stopped before it
|
||||
/* could record the reason.
|
||||
/* .RE
|
||||
/* .RE
|
||||
/* .IP
|
||||
/* This feature is available in Postfix 3.1 and later.
|
||||
/* .IP \fB-p\fR
|
||||
/* Produce a traditional sendmail-style queue listing.
|
||||
/* This option implements the traditional \fBmailq\fR command,
|
||||
@ -77,6 +125,8 @@
|
||||
/* .fi
|
||||
/* This program is designed to run with set-group ID privileges, so
|
||||
/* that it can connect to Postfix daemon processes.
|
||||
/* STANDARDS
|
||||
/* RFC 7159 (JSON notation)
|
||||
/* DIAGNOSTICS
|
||||
/* Problems are logged to \fBsyslogd\fR(8) and to the standard error
|
||||
/* stream.
|
||||
@ -161,6 +211,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -188,6 +243,7 @@
|
||||
#include <valid_hostname.h>
|
||||
#include <warn_stat.h>
|
||||
#include <events.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@ -208,6 +264,8 @@
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include <postqueue.h>
|
||||
|
||||
/*
|
||||
* WARNING WARNING WARNING
|
||||
*
|
||||
@ -241,6 +299,7 @@
|
||||
#define PQ_MODE_FLUSH_QUEUE 2 /* flush queue */
|
||||
#define PQ_MODE_FLUSH_SITE 3 /* flush site */
|
||||
#define PQ_MODE_FLUSH_FILE 4 /* flush message */
|
||||
#define PQ_MODE_JSON_LIST 5 /* JSON-format queue listing */
|
||||
|
||||
/*
|
||||
* Silly little macros (SLMs).
|
||||
@ -261,10 +320,9 @@ static const CONFIG_STR_TABLE str_table[] = {
|
||||
|
||||
/* show_queue - show queue status */
|
||||
|
||||
static void show_queue(void)
|
||||
static void show_queue(int mode)
|
||||
{
|
||||
const char *errstr;
|
||||
char buf[VSTREAM_BUFSIZE];
|
||||
VSTREAM *showq;
|
||||
int n;
|
||||
uid_t uid = getuid();
|
||||
@ -277,19 +335,20 @@ static void show_queue(void)
|
||||
errstr, (long) uid);
|
||||
|
||||
/*
|
||||
* Connect to the show queue service. Terminate silently when piping into
|
||||
* a program that terminates early.
|
||||
* Connect to the show queue service.
|
||||
*/
|
||||
if ((showq = mail_connect(MAIL_CLASS_PUBLIC, var_showq_service, BLOCKING)) != 0) {
|
||||
while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) {
|
||||
if (vstream_fwrite(VSTREAM_OUT, buf, n) != n
|
||||
|| vstream_fflush(VSTREAM_OUT) != 0) {
|
||||
if (errno == EPIPE)
|
||||
break;
|
||||
msg_fatal("write error: %m");
|
||||
}
|
||||
switch (mode) {
|
||||
case PQ_MODE_MAILQ_LIST:
|
||||
showq_compat(showq);
|
||||
break;
|
||||
case PQ_MODE_JSON_LIST:
|
||||
showq_json(showq);
|
||||
break;
|
||||
default:
|
||||
msg_panic("show_queue: unknown mode %d", mode);
|
||||
}
|
||||
if (vstream_fclose(showq) && errno != EPIPE)
|
||||
if (vstream_fclose(showq))
|
||||
msg_warn("close: %m");
|
||||
}
|
||||
|
||||
@ -308,21 +367,40 @@ static void show_queue(void)
|
||||
* directly. Just run the showq program in stand-alone mode.
|
||||
*/
|
||||
else if (geteuid() == 0) {
|
||||
char *showq_path;
|
||||
ARGV *argv;
|
||||
int stat;
|
||||
|
||||
msg_warn("Mail system is down -- accessing queue directly");
|
||||
showq_path = concatenate(var_daemon_dir, "/", var_showq_service,
|
||||
(char *) 0);
|
||||
argv = argv_alloc(6);
|
||||
argv_add(argv, var_showq_service, "-u", "-S", (char *) 0);
|
||||
argv_add(argv, showq_path, "-u", "-S", (char *) 0);
|
||||
for (n = 0; n < msg_verbose; n++)
|
||||
argv_add(argv, "-v", (char *) 0);
|
||||
argv_terminate(argv);
|
||||
stat = mail_run_foreground(var_daemon_dir, argv->argv);
|
||||
if ((showq = vstream_popen(O_RDONLY,
|
||||
CA_VSTREAM_POPEN_ARGV(argv->argv),
|
||||
CA_VSTREAM_POPEN_END)) == 0) {
|
||||
stat = -1;
|
||||
} else {
|
||||
switch (mode) {
|
||||
case PQ_MODE_MAILQ_LIST:
|
||||
showq_compat(showq);
|
||||
break;
|
||||
case PQ_MODE_JSON_LIST:
|
||||
showq_json(showq);
|
||||
break;
|
||||
default:
|
||||
msg_panic("show_queue: unknown mode %d", mode);
|
||||
}
|
||||
stat = vstream_pclose(showq);
|
||||
}
|
||||
argv_free(argv);
|
||||
if (stat != 0)
|
||||
msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE,
|
||||
"Error running %s/%s",
|
||||
var_daemon_dir, argv->argv[0]);
|
||||
"Error running %s", showq_path);
|
||||
myfree(showq_path);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -500,7 +578,7 @@ int main(int argc, char **argv)
|
||||
* mail configuration read routine. Don't do complex things until we have
|
||||
* completed initializations.
|
||||
*/
|
||||
while ((c = GETOPT(argc, argv, "c:fi:ps:v")) > 0) {
|
||||
while ((c = GETOPT(argc, argv, "c:fi:jps:v")) > 0) {
|
||||
switch (c) {
|
||||
case 'c': /* non-default configuration */
|
||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||
@ -517,6 +595,11 @@ int main(int argc, char **argv)
|
||||
mode = PQ_MODE_FLUSH_FILE;
|
||||
id_to_flush = optarg;
|
||||
break;
|
||||
case 'j':
|
||||
if (mode != PQ_MODE_DEFAULT)
|
||||
usage();
|
||||
mode = PQ_MODE_JSON_LIST;
|
||||
break;
|
||||
case 'p': /* traditional mailq */
|
||||
if (mode != PQ_MODE_DEFAULT)
|
||||
usage();
|
||||
@ -597,7 +680,8 @@ int main(int argc, char **argv)
|
||||
msg_panic("unknown operation mode: %d", mode);
|
||||
/* NOTREACHED */
|
||||
case PQ_MODE_MAILQ_LIST:
|
||||
show_queue();
|
||||
case PQ_MODE_JSON_LIST:
|
||||
show_queue(mode);
|
||||
exit(0);
|
||||
break;
|
||||
case PQ_MODE_FLUSH_SITE:
|
||||
|
35
postfix/src/postqueue/postqueue.h
Normal file
35
postfix/src/postqueue/postqueue.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* postqueue 5h
|
||||
/* SUMMARY
|
||||
/* postqueue internal interfaces
|
||||
/* SYNOPSIS
|
||||
/* #include <postqueue.h>
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* showq_compat.c
|
||||
*/
|
||||
extern void showq_compat(VSTREAM *);
|
||||
|
||||
/*
|
||||
* showq_json.c
|
||||
*/
|
||||
extern void showq_json(VSTREAM *);
|
||||
|
||||
/* 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
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
209
postfix/src/postqueue/showq_compat.c
Normal file
209
postfix/src/postqueue/showq_compat.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* showq_compat 8
|
||||
/* SUMMARY
|
||||
/* Sendmail mailq compatibitily adapter
|
||||
/* SYNOPSIS
|
||||
/* void showq_compat(
|
||||
/* VSTREAM *showq)
|
||||
/* DESCRIPTION
|
||||
/* This function converts a record stream from the showq(8)
|
||||
/* daemon to of an approximation of Sendmail mailq command
|
||||
/* output.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: out of memory, malformed showq(8) daemon output.
|
||||
/* 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
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
#include <stringops.h>
|
||||
#include <mymalloc.h>
|
||||
#include <msg.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_proto.h>
|
||||
#include <mail_queue.h>
|
||||
#include <mail_date.h>
|
||||
#include <mail_params.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include <postqueue.h>
|
||||
|
||||
/*
|
||||
* The enable_long_queue_ids parameter determines the output format.
|
||||
*
|
||||
* The historical output format for short queue IDs (inode number and time in
|
||||
* microseconds modulo 1) is not suitable for large inode numbers, but we
|
||||
* won't change it to avoid breaking compatibility with programs that parse
|
||||
* this output.
|
||||
*/
|
||||
#define S_STRING_FORMAT "%-11s %7s %-20s %s\n"
|
||||
#define S_SENDER_FORMAT "%-11s %7ld %20.20s %s\n"
|
||||
#define S_HEADINGS "-Queue ID-", "--Size--", \
|
||||
"----Arrival Time----", "-Sender/Recipient-------"
|
||||
|
||||
#define L_STRING_FORMAT "%-17s %8s %-19s %s\n"
|
||||
#define L_SENDER_FORMAT "%-17s %8ld %19.19s %s\n"
|
||||
#define L_HEADINGS "----Queue ID-----", "--Size--", \
|
||||
"---Arrival Time----", "--Sender/Recipient------"
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
|
||||
/* showq_message - report status for one message */
|
||||
|
||||
static unsigned long showq_message(VSTREAM *showq_stream)
|
||||
{
|
||||
static VSTRING *queue_name = 0;
|
||||
static VSTRING *queue_id = 0;
|
||||
static VSTRING *id_status = 0;
|
||||
static VSTRING *addr = 0;
|
||||
static VSTRING *why = 0;
|
||||
long arrival_time;
|
||||
long message_size;
|
||||
int message_status;
|
||||
char *saved_reason = mystrdup("");
|
||||
const char *show_reason;
|
||||
int padding;
|
||||
int showq_status;
|
||||
time_t time_t_arrival_time;
|
||||
|
||||
/*
|
||||
* One-time initialization.
|
||||
*/
|
||||
if (queue_name == 0) {
|
||||
queue_name = vstring_alloc(100);
|
||||
queue_id = vstring_alloc(100);
|
||||
id_status = vstring_alloc(100);
|
||||
addr = vstring_alloc(100);
|
||||
why = vstring_alloc(100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the message properties and sender address.
|
||||
*/
|
||||
if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
|
||||
RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
|
||||
RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
|
||||
RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time),
|
||||
RECV_ATTR_LONG(MAIL_ATTR_SIZE, &message_size),
|
||||
RECV_ATTR_STR(MAIL_ATTR_SENDER, addr),
|
||||
ATTR_TYPE_END) != 5)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
|
||||
/*
|
||||
* Decorate queue file names in specific states, then print the result
|
||||
* left-aligned, followed by other status info and the sender address
|
||||
* which is already in externalized RFC 5321 form.
|
||||
*/
|
||||
message_status = (strcmp(STR(queue_name), MAIL_QUEUE_ACTIVE) == 0 ? '*' :
|
||||
strcmp(STR(queue_name), MAIL_QUEUE_HOLD) == 0 ? '!' : ' ');
|
||||
vstring_sprintf(id_status, "%s%c", STR(queue_id), message_status);
|
||||
time_t_arrival_time = arrival_time;
|
||||
vstream_printf(var_long_queue_ids ?
|
||||
L_SENDER_FORMAT : S_SENDER_FORMAT, STR(id_status),
|
||||
message_size, asctime(localtime(&time_t_arrival_time)),
|
||||
STR(addr));
|
||||
|
||||
/*
|
||||
* Read zero or more (recipient, reason) pair(s) until attr_scan_more()
|
||||
* consumes a terminator. If the showq daemon messes up, don't try to
|
||||
* resynchronize.
|
||||
*/
|
||||
while ((showq_status = attr_scan_more(showq_stream)) > 0) {
|
||||
if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
|
||||
RECV_ATTR_STR(MAIL_ATTR_RECIP, addr),
|
||||
RECV_ATTR_STR(MAIL_ATTR_WHY, why),
|
||||
ATTR_TYPE_END) != 2)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
|
||||
/*
|
||||
* Don't output a "(reason)" line when no recipient has a reason, or
|
||||
* when the previous recipient has the same (non)reason as the
|
||||
* current recipient. Do output a "(reason unavailable)" when the
|
||||
* previous recipient has a reason, and the current recipient has
|
||||
* none.
|
||||
*/
|
||||
if (strcmp(saved_reason, STR(why)) != 0) {
|
||||
myfree(saved_reason);
|
||||
saved_reason = mystrdup(STR(why));
|
||||
show_reason = *saved_reason ? saved_reason : "reason unavailable";
|
||||
if ((padding = 76 - strlen(show_reason)) < 0)
|
||||
padding = 0;
|
||||
vstream_printf("%*s(%s)\n", padding, "", show_reason);
|
||||
}
|
||||
vstream_printf(var_long_queue_ids ?
|
||||
L_STRING_FORMAT : S_STRING_FORMAT,
|
||||
"", "", "", STR(addr));
|
||||
}
|
||||
if (showq_status < 0)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
myfree(saved_reason);
|
||||
return (message_size);
|
||||
}
|
||||
|
||||
/* showq_compat - legacy mailq-style output adapter */
|
||||
|
||||
void showq_compat(VSTREAM *showq_stream)
|
||||
{
|
||||
unsigned long file_count = 0;
|
||||
unsigned long queue_size = 0;
|
||||
int showq_status;
|
||||
|
||||
/*
|
||||
* Process zero or more queue file objects until attr_scan_more()
|
||||
* consumes a terminator.
|
||||
*/
|
||||
while ((showq_status = attr_scan_more(showq_stream)) > 0) {
|
||||
if (file_count > 0) {
|
||||
vstream_printf("\n");
|
||||
} else if (var_long_queue_ids) {
|
||||
vstream_printf(L_STRING_FORMAT, L_HEADINGS);
|
||||
} else {
|
||||
vstream_printf(S_STRING_FORMAT, S_HEADINGS);
|
||||
}
|
||||
queue_size += showq_message(showq_stream);
|
||||
file_count++;
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
if (showq_status < 0)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
|
||||
/*
|
||||
* Print the queue summary.
|
||||
*/
|
||||
if (file_count == 0)
|
||||
vstream_printf("Mail queue is empty\n");
|
||||
else {
|
||||
vstream_printf("\n-- %lu Kbytes in %lu Request%s.\n",
|
||||
queue_size / 1024, file_count,
|
||||
file_count == 1 ? "" : "s");
|
||||
}
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
213
postfix/src/postqueue/showq_json.c
Normal file
213
postfix/src/postqueue/showq_json.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* showq_json 8
|
||||
/* SUMMARY
|
||||
/* JSON queue status formatter
|
||||
/* SYNOPSIS
|
||||
/* void showq_json(
|
||||
/* VSTREAM *showq)
|
||||
/* DESCRIPTION
|
||||
/* This function converts showq(8) daemon output to JSON format.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: out of memory, malformed showq(8) daemon output.
|
||||
/* 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
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
#include <stringops.h>
|
||||
#include <mymalloc.h>
|
||||
#include <msg.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_proto.h>
|
||||
#include <mail_queue.h>
|
||||
#include <mail_date.h>
|
||||
#include <mail_params.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include <postqueue.h>
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
|
||||
/* json_quote - quote JSON string */
|
||||
|
||||
static char *json_quote(VSTRING *result, const char *text)
|
||||
{
|
||||
unsigned char *cp;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* We use short escape sequences for common control characters. Note that
|
||||
* RFC 4627 allows "/" (0x2F) to be sent without quoting. Differences
|
||||
* with RFC 4627: we send DEL (0x7f) as \u007F; the result remains RFC
|
||||
* 4627 complaint.
|
||||
*/
|
||||
VSTRING_RESET(result);
|
||||
for (cp = (unsigned char *) text; (ch = *cp) != 0; cp++) {
|
||||
if (UNEXPECTED(ISCNTRL(ch))) {
|
||||
switch (ch) {
|
||||
case '\b':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
VSTRING_ADDCH(result, 'b');
|
||||
break;
|
||||
case '\f':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
VSTRING_ADDCH(result, 'f');
|
||||
break;
|
||||
case '\n':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
VSTRING_ADDCH(result, 'n');
|
||||
break;
|
||||
case '\r':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
VSTRING_ADDCH(result, 'r');
|
||||
break;
|
||||
case '\t':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
VSTRING_ADDCH(result, 't');
|
||||
break;
|
||||
default:
|
||||
vstring_sprintf(result, "\\u%04X", ch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
case '"':
|
||||
VSTRING_ADDCH(result, '\\');
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
VSTRING_ADDCH(result, ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
VSTRING_TERMINATE(result);
|
||||
|
||||
/*
|
||||
* Force the result to be UTF-8 (with SMTPUTF8 enabled) or ASCII (with
|
||||
* SMTPUTF8 disabled).
|
||||
*/
|
||||
printable(STR(result), '?');
|
||||
return (STR(result));
|
||||
}
|
||||
|
||||
/* json_message - report status for one message */
|
||||
|
||||
static void format_json(VSTREAM *showq_stream)
|
||||
{
|
||||
static VSTRING *queue_name = 0;
|
||||
static VSTRING *queue_id = 0;
|
||||
static VSTRING *addr = 0;
|
||||
static VSTRING *why = 0;
|
||||
static VSTRING *quote_buf = 0;
|
||||
long arrival_time;
|
||||
long message_size;
|
||||
int showq_status;
|
||||
int rcpt_count = 0;
|
||||
|
||||
/*
|
||||
* One-time initialization.
|
||||
*/
|
||||
if (queue_name == 0) {
|
||||
queue_name = vstring_alloc(100);
|
||||
queue_id = vstring_alloc(100);
|
||||
addr = vstring_alloc(100);
|
||||
why = vstring_alloc(100);
|
||||
quote_buf = vstring_alloc(100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the message properties and sender address.
|
||||
*/
|
||||
if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
|
||||
RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
|
||||
RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
|
||||
RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time),
|
||||
RECV_ATTR_LONG(MAIL_ATTR_SIZE, &message_size),
|
||||
RECV_ATTR_STR(MAIL_ATTR_SENDER, addr),
|
||||
ATTR_TYPE_END) != 5)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
vstream_printf("{");
|
||||
vstream_printf("\"queue_name\": \"%s\",",
|
||||
json_quote(quote_buf, STR(queue_name)));
|
||||
vstream_printf("\"queue_id\": \"%s\",",
|
||||
json_quote(quote_buf, STR(queue_id)));
|
||||
vstream_printf("\"arrival_time\": %ld,", arrival_time);
|
||||
vstream_printf("\"message_size\": %ld,", message_size);
|
||||
vstream_printf("\"sender\": \"%s\",",
|
||||
json_quote(quote_buf, STR(addr)));
|
||||
|
||||
/*
|
||||
Read zero or more (recipient, reason) pair(s) until attr_scan_more()
|
||||
* consumes a terminator. If the showq daemon messes up, don't try to
|
||||
* resynchronize.
|
||||
*/
|
||||
vstream_printf("\"recipients\": [");
|
||||
for (rcpt_count = 0; (showq_status = attr_scan_more(showq_stream)) > 0; rcpt_count++) {
|
||||
if (rcpt_count > 0)
|
||||
vstream_printf(",");
|
||||
vstream_printf("{");
|
||||
if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
|
||||
RECV_ATTR_STR(MAIL_ATTR_RECIP, addr),
|
||||
RECV_ATTR_STR(MAIL_ATTR_WHY, why),
|
||||
ATTR_TYPE_END) != 2)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
vstream_printf("\"address\": \"%s\"",
|
||||
json_quote(quote_buf, STR(addr)));
|
||||
if (LEN(why) > 0)
|
||||
vstream_printf(",\"delay_reason\": \"%s\",",
|
||||
json_quote(quote_buf, STR(why)));
|
||||
vstream_printf("}");
|
||||
}
|
||||
vstream_printf("]");
|
||||
if (showq_status < 0)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
vstream_printf("}\n");
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
|
||||
/* showq_json - streaming JSON-format output adapter */
|
||||
|
||||
void showq_json(VSTREAM *showq_stream)
|
||||
{
|
||||
int showq_status;
|
||||
|
||||
/*
|
||||
* Emit zero or more queue file objects until attr_scan_more()
|
||||
* consumes a terminator.
|
||||
*/
|
||||
while ((showq_status = attr_scan_more(showq_stream)) > 0) {
|
||||
format_json(showq_stream);
|
||||
}
|
||||
if (showq_status < 0)
|
||||
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
|
||||
}
|
@ -7,7 +7,8 @@
|
||||
/* \fBshowq\fR [generic Postfix daemon options]
|
||||
/* DESCRIPTION
|
||||
/* The \fBshowq\fR(8) daemon reports the Postfix mail queue status.
|
||||
/* It is the program that emulates the sendmail `mailq' command.
|
||||
/* The output is meant to be formatted by the postqueue(1) command,
|
||||
/* as it emulates the Sendmail `mailq' command.
|
||||
/*
|
||||
/* The \fBshowq\fR(8) daemon can also be run in stand-alone mode
|
||||
/* by the superuser. This mode of operation is used to emulate
|
||||
@ -89,6 +90,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -140,18 +146,6 @@
|
||||
int var_dup_filter_limit;
|
||||
char *var_empty_addr;
|
||||
|
||||
#define S_STRING_FORMAT "%-10s %8s %-20s %s\n"
|
||||
#define S_SENDER_FORMAT "%-11s %7ld %20.20s %s\n"
|
||||
#define S_DROP_FORMAT "%-10s%c %7ld %20.20s (maildrop queue, sender UID %u)\n"
|
||||
#define S_HEADINGS "-Queue ID-", "--Size--", \
|
||||
"----Arrival Time----", "-Sender/Recipient-------"
|
||||
|
||||
#define L_STRING_FORMAT "%-17s %8s %-19s %s\n"
|
||||
#define L_SENDER_FORMAT "%-17s %8ld %19.19s %s\n"
|
||||
#define L_DROP_FORMAT "%-16s%c %8ld %19.19s (maildrop queue, sender UID %u)\n"
|
||||
#define L_HEADINGS "----Queue ID-----", "--Size--", \
|
||||
"---Arrival Time----", "--Sender/Recipient------"
|
||||
|
||||
static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *,
|
||||
HTABLE *);
|
||||
|
||||
@ -167,15 +161,30 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
int rec_type;
|
||||
time_t arrival_time = 0;
|
||||
char *start;
|
||||
long msg_size = 0;
|
||||
long msg_size = size;
|
||||
BOUNCE_LOG *logfile;
|
||||
HTABLE *dup_filter = 0;
|
||||
RCPT_BUF *rcpt_buf = 0;
|
||||
DSN_BUF *dsn_buf = 0;
|
||||
char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' :
|
||||
strcmp(queue, MAIL_QUEUE_HOLD) == 0 ? '!' : ' ');
|
||||
int sender_seen = 0;
|
||||
int msg_size_ok = 0;
|
||||
|
||||
/*
|
||||
* Let the optimizer worry about eliminating duplicate code.
|
||||
*/
|
||||
#define SHOWQ_CLEANUP_AND_RETURN { \
|
||||
if (sender_seen > 0) \
|
||||
attr_print(client, ATTR_FLAG_NONE, ATTR_TYPE_END); \
|
||||
vstring_free(buf); \
|
||||
vstring_free(printable_quoted_addr); \
|
||||
if (rcpt_buf) \
|
||||
rcpb_free(rcpt_buf); \
|
||||
if (dsn_buf) \
|
||||
dsb_free(dsn_buf); \
|
||||
if (dup_filter) \
|
||||
htable_free(dup_filter, (void (*) (void *)) 0); \
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX addresses in defer logfiles are in printable quoted form, while
|
||||
* addresses in message envelope records are in raw unquoted form. This
|
||||
@ -192,12 +201,16 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
msg_info("record %c %s", rec_type, printable(start, '?'));
|
||||
switch (rec_type) {
|
||||
case REC_TYPE_TIME:
|
||||
arrival_time = atol(start);
|
||||
/* TODO: parse seconds and microseconds. */
|
||||
if (arrival_time == 0)
|
||||
arrival_time = atol(start);
|
||||
break;
|
||||
case REC_TYPE_SIZE:
|
||||
if (msg_size == 0) {
|
||||
if ((msg_size_ok = ((msg_size = atol(start)) > 0)) == 0) {
|
||||
msg_warn("%s: malformed size record: %.100s",
|
||||
if (msg_size_ok == 0) {
|
||||
msg_size_ok = (alldig(start) && (msg_size = atol(start)) >= 0);
|
||||
if (msg_size_ok == 0) {
|
||||
msg_warn("%s: malformed size record: %.100s "
|
||||
"-- using file size instead",
|
||||
id, printable(start, '?'));
|
||||
msg_size = size;
|
||||
}
|
||||
@ -208,25 +221,40 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
start = var_empty_addr;
|
||||
quote_822_local(printable_quoted_addr, start);
|
||||
printable(STR(printable_quoted_addr), '?');
|
||||
/* quote_822_local() saves buf, so we can reuse its space. */
|
||||
vstring_sprintf(buf, "%s%c", id, status);
|
||||
vstream_fprintf(client, var_long_queue_ids ?
|
||||
L_SENDER_FORMAT : S_SENDER_FORMAT, STR(buf),
|
||||
msg_size > 0 ? msg_size : size, arrival_time > 0 ?
|
||||
asctime(localtime(&arrival_time)) :
|
||||
asctime(localtime(&mtime)),
|
||||
STR(printable_quoted_addr));
|
||||
if (sender_seen++ > 0) {
|
||||
msg_warn("%s: duplicate sender address: %s "
|
||||
"-- skipping remainder of this file",
|
||||
id, STR(printable_quoted_addr));
|
||||
SHOWQ_CLEANUP_AND_RETURN;
|
||||
}
|
||||
attr_print(client, ATTR_FLAG_MORE,
|
||||
SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue),
|
||||
SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id),
|
||||
SEND_ATTR_LONG(MAIL_ATTR_TIME, arrival_time > 0 ?
|
||||
arrival_time : mtime),
|
||||
SEND_ATTR_LONG(MAIL_ATTR_SIZE, msg_size),
|
||||
SEND_ATTR_STR(MAIL_ATTR_SENDER,
|
||||
STR(printable_quoted_addr)),
|
||||
ATTR_TYPE_END);
|
||||
break;
|
||||
case REC_TYPE_RCPT:
|
||||
if (sender_seen == 0) {
|
||||
msg_warn("%s: missing sender address: %s "
|
||||
"-- skipping remainder of this file",
|
||||
id, STR(printable_quoted_addr));
|
||||
SHOWQ_CLEANUP_AND_RETURN;
|
||||
}
|
||||
if (*start == 0) /* can't happen? */
|
||||
start = var_empty_addr;
|
||||
quote_822_local(printable_quoted_addr, start);
|
||||
printable(STR(printable_quoted_addr), '?');
|
||||
if (dup_filter == 0
|
||||
|| htable_locate(dup_filter, STR(printable_quoted_addr)) == 0)
|
||||
vstream_fprintf(client, var_long_queue_ids ?
|
||||
L_STRING_FORMAT : S_STRING_FORMAT,
|
||||
"", "", "", STR(printable_quoted_addr));
|
||||
attr_print(client, ATTR_FLAG_MORE,
|
||||
SEND_ATTR_STR(MAIL_ATTR_RECIP,
|
||||
STR(printable_quoted_addr)),
|
||||
SEND_ATTR_STR(MAIL_ATTR_WHY, ""),
|
||||
ATTR_TYPE_END);
|
||||
break;
|
||||
case REC_TYPE_MESG:
|
||||
if (msg_size_ok && vstream_fseek(qfile, msg_size, SEEK_CUR) < 0)
|
||||
@ -237,18 +265,22 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
}
|
||||
|
||||
/*
|
||||
* With the heading printed, see if there is a defer logfile. The
|
||||
* defer logfile is not necessarily complete: delivery may be
|
||||
* Before listing any recipients from the queue file, try to list
|
||||
* recipients from the corresponding defer logfile with per-recipient
|
||||
* descriptions why delivery was deferred.
|
||||
*
|
||||
* The defer logfile is not necessarily complete: delivery may be
|
||||
* interrupted (postfix stop or reload) before all recipients have
|
||||
* been tried.
|
||||
*
|
||||
* Therefore we keep a record of recipients found in the defer logfile,
|
||||
* and try to avoid listing those recipients again when processing
|
||||
* the remainder of the queue file.
|
||||
* recipients from the queue file.
|
||||
*/
|
||||
if (rec_type == REC_TYPE_FROM
|
||||
&& dup_filter == 0
|
||||
&& (logfile = bounce_log_open(MAIL_QUEUE_DEFER, id, O_RDONLY, 0)) != 0) {
|
||||
if (dup_filter != 0)
|
||||
msg_panic("showq_report: attempt to reuse duplicate filter");
|
||||
dup_filter = htable_create(var_dup_filter_limit);
|
||||
if (rcpt_buf == 0)
|
||||
rcpt_buf = rcpb_create();
|
||||
@ -259,14 +291,7 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
|
||||
}
|
||||
}
|
||||
vstring_free(buf);
|
||||
vstring_free(printable_quoted_addr);
|
||||
if (rcpt_buf)
|
||||
rcpb_free(rcpt_buf);
|
||||
if (dsn_buf)
|
||||
dsb_free(dsn_buf);
|
||||
if (dup_filter)
|
||||
htable_free(dup_filter, (void (*) (void *)) 0);
|
||||
SHOWQ_CLEANUP_AND_RETURN;
|
||||
}
|
||||
|
||||
/* showq_reasons - show deferral reasons */
|
||||
@ -274,8 +299,6 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
|
||||
DSN_BUF *dsn_buf, HTABLE *dup_filter)
|
||||
{
|
||||
char *saved_reason = 0;
|
||||
int padding;
|
||||
RECIPIENT *rcpt = &rcpt_buf->rcpt;
|
||||
DSN *dsn = &dsn_buf->dsn;
|
||||
|
||||
@ -289,23 +312,11 @@ static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
|
||||
if (htable_locate(dup_filter, rcpt->address) == 0)
|
||||
htable_enter(dup_filter, rcpt->address, (void *) 0);
|
||||
|
||||
/*
|
||||
* Don't print the reason when the previous recipient had the same
|
||||
* problem.
|
||||
*/
|
||||
if (saved_reason == 0 || strcmp(saved_reason, dsn->reason) != 0) {
|
||||
if (saved_reason)
|
||||
myfree(saved_reason);
|
||||
saved_reason = mystrdup(dsn->reason);
|
||||
if ((padding = 76 - strlen(saved_reason)) < 0)
|
||||
padding = 0;
|
||||
vstream_fprintf(client, "%*s(%s)\n", padding, "", saved_reason);
|
||||
}
|
||||
vstream_fprintf(client, var_long_queue_ids ? L_STRING_FORMAT :
|
||||
S_STRING_FORMAT, "", "", "", rcpt->address);
|
||||
attr_print(client, ATTR_FLAG_MORE,
|
||||
SEND_ATTR_STR(MAIL_ATTR_RECIP, rcpt->address),
|
||||
SEND_ATTR_STR(MAIL_ATTR_WHY, dsn->reason),
|
||||
ATTR_TYPE_END);
|
||||
}
|
||||
if (saved_reason)
|
||||
myfree(saved_reason);
|
||||
}
|
||||
|
||||
|
||||
@ -318,7 +329,6 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
|
||||
int status;
|
||||
char *id;
|
||||
int file_count;
|
||||
unsigned long queue_size = 0;
|
||||
struct stat st;
|
||||
struct queue_info {
|
||||
char *name; /* queue name */
|
||||
@ -368,30 +378,14 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
|
||||
saved_id = mystrdup(id);
|
||||
status = mail_open_ok(qp->name, id, &st, &path);
|
||||
if (status == MAIL_OPEN_YES) {
|
||||
if (file_count == 0) {
|
||||
if (var_long_queue_ids)
|
||||
vstream_fprintf(client, L_STRING_FORMAT, L_HEADINGS);
|
||||
else
|
||||
vstream_fprintf(client, S_STRING_FORMAT, S_HEADINGS);
|
||||
} else
|
||||
vstream_fprintf(client, "\n");
|
||||
if ((qfile = mail_queue_open(qp->name, id, O_RDONLY, 0)) != 0) {
|
||||
queue_size += st.st_size;
|
||||
showq_report(client, qp->name, id, qfile, (long) st.st_size,
|
||||
st.st_mtime);
|
||||
if (vstream_fclose(qfile))
|
||||
msg_warn("close file %s %s: %m", qp->name, id);
|
||||
} else if (strcmp(qp->name, MAIL_QUEUE_MAILDROP) == 0) {
|
||||
queue_size += st.st_size;
|
||||
vstream_fprintf(client, var_long_queue_ids ?
|
||||
L_DROP_FORMAT : S_DROP_FORMAT, id, ' ',
|
||||
(long) st.st_size,
|
||||
asctime(localtime(&st.st_mtime)),
|
||||
(unsigned) st.st_uid);
|
||||
} else if (errno != ENOENT)
|
||||
msg_fatal("open %s %s: %m", qp->name, id);
|
||||
file_count++;
|
||||
vstream_fflush(client);
|
||||
} else if (errno != ENOENT) {
|
||||
msg_warn("open %s %s: %m", qp->name, id);
|
||||
}
|
||||
}
|
||||
vstream_fflush(client);
|
||||
}
|
||||
@ -399,13 +393,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
|
||||
myfree(saved_id);
|
||||
scan_dir_close(scan);
|
||||
}
|
||||
if (file_count == 0)
|
||||
vstream_fprintf(client, "Mail queue is empty\n");
|
||||
else {
|
||||
vstream_fprintf(client, "\n-- %lu Kbytes in %d Request%s.\n",
|
||||
queue_size / 1024, file_count,
|
||||
file_count == 1 ? "" : "s");
|
||||
}
|
||||
attr_print(client, ATTR_FLAG_NONE, ATTR_TYPE_END);
|
||||
}
|
||||
|
||||
MAIL_VERSION_STAMP_DECLARE;
|
||||
|
@ -567,16 +567,21 @@ extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *);
|
||||
/*
|
||||
* smtp_trouble.c
|
||||
*/
|
||||
#define SMTP_THROTTLE 1
|
||||
#define SMTP_NOTHROTTLE 0
|
||||
extern int smtp_sess_fail(SMTP_STATE *);
|
||||
extern int PRINTFLIKE(4, 5) smtp_site_fail(SMTP_STATE *, const char *,
|
||||
SMTP_RESP *, const char *,...);
|
||||
extern int PRINTFLIKE(4, 5) smtp_mesg_fail(SMTP_STATE *, const char *,
|
||||
extern int PRINTFLIKE(5, 6) smtp_misc_fail(SMTP_STATE *, int, const char *,
|
||||
SMTP_RESP *, const char *,...);
|
||||
extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *,
|
||||
const char *, SMTP_RESP *,
|
||||
const char *,...);
|
||||
extern int smtp_stream_except(SMTP_STATE *, int, const char *);
|
||||
|
||||
#define smtp_site_fail(state, mta, resp, ...) \
|
||||
smtp_misc_fail((state), SMTP_THROTTLE, (mta), (resp), __VA_ARGS__)
|
||||
#define smtp_mesg_fail(state, mta, resp, ...) \
|
||||
smtp_misc_fail((state), SMTP_NOTHROTTLE, (mta), (resp), __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* smtp_unalias.c
|
||||
*/
|
||||
|
@ -935,10 +935,17 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
* authentication. If the server doesn't announce SASL support over
|
||||
* plaintext connections, then we don't want delivery to fail with
|
||||
* "relay access denied".
|
||||
*
|
||||
* If TLS is opportunistic, don't throttle the destination, otherwise if
|
||||
* the mail is volume is high enough we may have difficulty ever
|
||||
* draining even the deferred mail, as new mail provides a constant
|
||||
* stream of negative feedback.
|
||||
*/
|
||||
if (PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE)
|
||||
RETRY_AS_PLAINTEXT;
|
||||
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||
return (smtp_misc_fail(state, state->tls->level == TLS_LEV_MAY ?
|
||||
SMTP_NOTHROTTLE : SMTP_THROTTLE,
|
||||
DSN_BY_LOCAL_MTA,
|
||||
SMTP_RESP_FAKE(&fake, "4.7.5"),
|
||||
"Cannot start TLS: handshake failure"));
|
||||
}
|
||||
|
@ -32,6 +32,13 @@
|
||||
/* SMTP_STATE *state;
|
||||
/* int exception;
|
||||
/* const char *description;
|
||||
/* AUXILIARY FUNCTIONS
|
||||
/* int smtp_misc_fail(state, throttle, mta_name, resp, format, ...)
|
||||
/* SMTP_STATE *state;
|
||||
/* int throttle;
|
||||
/* const char *mta_name;
|
||||
/* SMTP_RESP *resp;
|
||||
/* const char *format;
|
||||
/* DESCRIPTION
|
||||
/* This module handles all non-fatal errors that can happen while
|
||||
/* attempting to deliver mail via SMTP, and implements the policy
|
||||
@ -82,6 +89,13 @@
|
||||
/* remaining recipients.
|
||||
/* The result is non-zero.
|
||||
/*
|
||||
/* smtp_misc_fail() provides a more detailed interface than
|
||||
/* smtp_site_fail() and smtp_mesg_fail(), which are convenience
|
||||
/* wrappers around smtp_misc_fail(). The throttle argument
|
||||
/* is either SMTP_THROTTLE or SMTP_NOTHROTTLE; it is used only
|
||||
/* in the "soft error, final server" policy, and determines
|
||||
/* whether a destination will be marked as problematic.
|
||||
/*
|
||||
/* smtp_rcpt_fail() handles the case where a recipient is not
|
||||
/* accepted by the server for reasons other than that the server
|
||||
/* recipient limit is reached.
|
||||
@ -162,9 +176,6 @@
|
||||
#include "smtp.h"
|
||||
#include "smtp_sasl.h"
|
||||
|
||||
#define SMTP_THROTTLE 1
|
||||
#define SMTP_NOTHROTTLE 0
|
||||
|
||||
/* smtp_check_code - check response code */
|
||||
|
||||
static void smtp_check_code(SMTP_SESSION *session, int code)
|
||||
@ -310,10 +321,10 @@ static void vsmtp_fill_dsn(SMTP_STATE *state, const char *mta_name,
|
||||
reply ? DSB_DTYPE_SMTP : DSB_DTYPE_NONE, reply);
|
||||
}
|
||||
|
||||
/* smtp_site_fail - throttle this queue; skip, defer or bounce all recipients */
|
||||
/* smtp_misc_fail - maybe throttle queue; skip/defer/bounce all recipients */
|
||||
|
||||
int smtp_site_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp,
|
||||
const char *format,...)
|
||||
int smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
|
||||
SMTP_RESP *resp, const char *format,...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -330,30 +341,7 @@ int smtp_site_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp,
|
||||
/*
|
||||
* Skip, defer or bounce recipients, and throttle this queue.
|
||||
*/
|
||||
return (smtp_bulk_fail(state, SMTP_THROTTLE));
|
||||
}
|
||||
|
||||
/* smtp_mesg_fail - skip, defer or bounce all recipients; no queue throttle */
|
||||
|
||||
int smtp_mesg_fail(SMTP_STATE *state, const char *mta_name, SMTP_RESP *resp,
|
||||
const char *format,...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
va_start(ap, format);
|
||||
vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (state->session && mta_name)
|
||||
smtp_check_code(state->session, resp->code);
|
||||
|
||||
/*
|
||||
* Skip, defer or bounce recipients, but don't throttle this queue.
|
||||
*/
|
||||
return (smtp_bulk_fail(state, SMTP_NOTHROTTLE));
|
||||
return (smtp_bulk_fail(state, throttle));
|
||||
}
|
||||
|
||||
/* smtp_rcpt_fail - skip, defer, or bounce recipient */
|
||||
|
@ -110,6 +110,7 @@ CHECK_VAL_HELPER_DCL(ATTR, ATTR_SCAN_SLAVE_FN);
|
||||
#define attr_vprint attr_vprint0
|
||||
#define attr_scan attr_scan0
|
||||
#define attr_vscan attr_vscan0
|
||||
#define attr_scan_more attr_scan_more0
|
||||
|
||||
/*
|
||||
* attr_print64.c.
|
||||
@ -122,6 +123,7 @@ extern int attr_vprint64(VSTREAM *, int, va_list);
|
||||
*/
|
||||
extern int WARN_UNUSED_RESULT attr_scan64(VSTREAM *, int,...);
|
||||
extern int WARN_UNUSED_RESULT attr_vscan64(VSTREAM *, int, va_list);
|
||||
extern int WARN_UNUSED_RESULT attr_scan_more64(VSTREAM *);
|
||||
|
||||
/*
|
||||
* attr_print0.c.
|
||||
@ -134,12 +136,14 @@ extern int attr_vprint0(VSTREAM *, int, va_list);
|
||||
*/
|
||||
extern int WARN_UNUSED_RESULT attr_scan0(VSTREAM *, int,...);
|
||||
extern int WARN_UNUSED_RESULT attr_vscan0(VSTREAM *, int, va_list);
|
||||
extern int WARN_UNUSED_RESULT attr_scan_more0(VSTREAM *);
|
||||
|
||||
/*
|
||||
* attr_scan_plain.c.
|
||||
*/
|
||||
extern int attr_print_plain(VSTREAM *, int,...);
|
||||
extern int attr_vprint_plain(VSTREAM *, int, va_list);
|
||||
extern int attr_scan_more_plain(VSTREAM *);
|
||||
|
||||
/*
|
||||
* attr_print_plain.c.
|
||||
@ -147,7 +151,6 @@ extern int attr_vprint_plain(VSTREAM *, int, va_list);
|
||||
extern int WARN_UNUSED_RESULT attr_scan_plain(VSTREAM *, int,...);
|
||||
extern int WARN_UNUSED_RESULT attr_vscan_plain(VSTREAM *, int, va_list);
|
||||
|
||||
|
||||
/*
|
||||
* Attribute names for testing the compatibility of the read and write
|
||||
* routines.
|
||||
|
@ -7,15 +7,18 @@
|
||||
/* #include <attr.h>
|
||||
/*
|
||||
/* int attr_scan0(fp, flags, type, name, ..., ATTR_TYPE_END)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* int type;
|
||||
/* char *name;
|
||||
/*
|
||||
/* int attr_vscan0(fp, flags, ap)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* va_list ap;
|
||||
/*
|
||||
/* int attr_scan_more0(fp)
|
||||
/* VSTREAM *fp;
|
||||
/* DESCRIPTION
|
||||
/* attr_scan0() takes zero or more (name, value) request attributes
|
||||
/* and recovers the attribute values from the byte stream that was
|
||||
@ -24,6 +27,11 @@
|
||||
/* attr_vscan0() provides an alternative interface that is convenient
|
||||
/* for calling from within a variadic function.
|
||||
/*
|
||||
/* attr_scan_more0() returns 0 when a terminator is found (and
|
||||
/* consumes that terminator), returns 1 when more input is
|
||||
/* expected (without consuming input), and returns -1 otherwise
|
||||
/* (error).
|
||||
/*
|
||||
/* The input stream is formatted as follows, where (item)* stands
|
||||
/* for zero or more instances of the specified item, and where
|
||||
/* (item1 | item2) stands for choice:
|
||||
@ -144,6 +152,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -345,14 +358,14 @@ int attr_vscan0(VSTREAM *fp, int flags, va_list ap)
|
||||
/*
|
||||
* See if the caller asks for this attribute.
|
||||
*/
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
&& strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
|
||||
wanted_type = ATTR_TYPE_CLOSE;
|
||||
wanted_name = "(any attribute name or '}')";
|
||||
/* Advance in the input stream. */
|
||||
continue;
|
||||
} else if (wanted_type == ATTR_TYPE_CLOSE
|
||||
&& strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
&& strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
/* Advance in the argument list. */
|
||||
wanted_type = -1;
|
||||
break;
|
||||
@ -450,6 +463,30 @@ int attr_scan0(VSTREAM *fp, int flags,...)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* attr_scan_more0 - look ahead for more */
|
||||
|
||||
int attr_scan_more0(VSTREAM *fp)
|
||||
{
|
||||
int ch;
|
||||
|
||||
switch (ch = VSTREAM_GETC(fp)) {
|
||||
case 0:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: terminator (consumed)", VSTREAM_PATH(fp));
|
||||
return (0);
|
||||
case VSTREAM_EOF:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: EOF", VSTREAM_PATH(fp));
|
||||
return (-1);
|
||||
default:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: non-terminator '%c' (lookahead)",
|
||||
VSTREAM_PATH(fp), ch);
|
||||
(void) vstream_ungetc(fp, ch);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
|
@ -7,15 +7,18 @@
|
||||
/* #include <attr.h>
|
||||
/*
|
||||
/* int attr_scan64(fp, flags, type, name, ..., ATTR_TYPE_END)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* int type;
|
||||
/* char *name;
|
||||
/*
|
||||
/* int attr_vscan64(fp, flags, ap)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* va_list ap;
|
||||
/*
|
||||
/* int attr_scan_more64(fp)
|
||||
/* VSTREAM *fp;
|
||||
/* DESCRIPTION
|
||||
/* attr_scan64() takes zero or more (name, value) request attributes
|
||||
/* and recovers the attribute values from the byte stream that was
|
||||
@ -24,6 +27,11 @@
|
||||
/* attr_vscan64() provides an alternative interface that is convenient
|
||||
/* for calling from within a variadic function.
|
||||
/*
|
||||
/* attr_scan_more64() returns 0 when a terminator is found
|
||||
/* (and consumes that terminator), returns 1 when more input
|
||||
/* is expected (without consuming input), and returns -1
|
||||
/* otherwise (error).
|
||||
/*
|
||||
/* The input stream is formatted as follows, where (item)* stands
|
||||
/* for zero or more instances of the specified item, and where
|
||||
/* (item1 | item2) stands for choice:
|
||||
@ -146,6 +154,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -348,14 +361,14 @@ int attr_vscan64(VSTREAM *fp, int flags, va_list ap)
|
||||
/*
|
||||
* See if the caller asks for this attribute.
|
||||
*/
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
|
||||
wanted_type = ATTR_TYPE_CLOSE;
|
||||
wanted_name = "(any attribute name or '}')";
|
||||
/* Advance in the input stream. */
|
||||
continue;
|
||||
} else if (wanted_type == ATTR_TYPE_CLOSE
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
/* Advance in the argument list. */
|
||||
wanted_type = -1;
|
||||
break;
|
||||
@ -509,6 +522,30 @@ int attr_scan64(VSTREAM *fp, int flags,...)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* attr_scan_more64 - look ahead for more */
|
||||
|
||||
int attr_scan_more64(VSTREAM *fp)
|
||||
{
|
||||
int ch;
|
||||
|
||||
switch (ch = VSTREAM_GETC(fp)) {
|
||||
case '\n':
|
||||
if (msg_verbose)
|
||||
msg_info("%s: terminator (consumed)", VSTREAM_PATH(fp));
|
||||
return (0);
|
||||
case VSTREAM_EOF:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: EOF", VSTREAM_PATH(fp));
|
||||
return (-1);
|
||||
default:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: non-terminator '%c' (lookahead)",
|
||||
VSTREAM_PATH(fp), ch);
|
||||
(void) vstream_ungetc(fp, ch);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
|
@ -7,15 +7,18 @@
|
||||
/* #include <attr.h>
|
||||
/*
|
||||
/* int attr_scan_plain(fp, flags, type, name, ..., ATTR_TYPE_END)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* int type;
|
||||
/* char *name;
|
||||
/*
|
||||
/* int attr_vscan_plain(fp, flags, ap)
|
||||
/* VSTREAM fp;
|
||||
/* VSTREAM *fp;
|
||||
/* int flags;
|
||||
/* va_list ap;
|
||||
/*
|
||||
/* int attr_scan_more_plain(fp)
|
||||
/* VSTREAM *fp;
|
||||
/* DESCRIPTION
|
||||
/* attr_scan_plain() takes zero or more (name, value) request attributes
|
||||
/* and recovers the attribute values from the byte stream that was
|
||||
@ -24,6 +27,11 @@
|
||||
/* attr_vscan_plain() provides an alternative interface that is convenient
|
||||
/* for calling from within a variadic function.
|
||||
/*
|
||||
/* attr_scan_more_plain() returns 0 when a terminator is found
|
||||
/* (and consumes that terminator), returns 1 when more input
|
||||
/* is expected (without consuming input), and returns -1
|
||||
/* otherwise (error).
|
||||
/*
|
||||
/* The input stream is formatted as follows, where (item)* stands
|
||||
/* for zero or more instances of the specified item, and where
|
||||
/* (item1 | item2) stands for choice:
|
||||
@ -144,6 +152,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -361,14 +374,14 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
|
||||
/*
|
||||
* See if the caller asks for this attribute.
|
||||
*/
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
|
||||
if (wanted_type == ATTR_TYPE_HASH
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
|
||||
wanted_type = ATTR_TYPE_CLOSE;
|
||||
wanted_name = "(any attribute name or '}')";
|
||||
/* Advance in the input stream. */
|
||||
continue;
|
||||
} else if (wanted_type == ATTR_TYPE_CLOSE
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
&& ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
|
||||
/* Advance in the argument list. */
|
||||
wanted_type = -1;
|
||||
break;
|
||||
@ -492,6 +505,30 @@ int attr_scan_plain(VSTREAM *fp, int flags,...)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* attr_scan_more_plain - look ahead for more */
|
||||
|
||||
int attr_scan_more_plain(VSTREAM *fp)
|
||||
{
|
||||
int ch;
|
||||
|
||||
switch (ch = VSTREAM_GETC(fp)) {
|
||||
case '\n':
|
||||
if (msg_verbose)
|
||||
msg_info("%s: terminator (consumed)", VSTREAM_PATH(fp));
|
||||
return (0);
|
||||
case VSTREAM_EOF:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: EOF", VSTREAM_PATH(fp));
|
||||
return (-1);
|
||||
default:
|
||||
if (msg_verbose)
|
||||
msg_info("%s: non-terminator '%c' (lookahead)",
|
||||
VSTREAM_PATH(fp), ch);
|
||||
(void) vstream_ungetc(fp, ch);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
|
@ -399,7 +399,8 @@
|
||||
/* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND).
|
||||
/*
|
||||
/* vstream_peek_data() returns a pointer to the unread bytes
|
||||
/* that exist according to vstream_peek().
|
||||
/* that exist according to vstream_peek(), or null if no unread
|
||||
/* bytes are available.
|
||||
/*
|
||||
/* vstream_setjmp() saves processing context and makes that context
|
||||
/* available for use with vstream_longjmp(). Normally, vstream_setjmp()
|
||||
|
Loading…
x
Reference in New Issue
Block a user