2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 05:07:58 +00:00

postfix-3.1-20151129

This commit is contained in:
Wietse Venema 2015-11-29 00:00:00 -05:00 committed by Viktor Dukhovni
parent fd122dde8c
commit 6b8ab5dd1f
25 changed files with 1038 additions and 198 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 &lt;CR&gt;&lt;LF&gt; 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>

View File

@ -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>

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View 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
/*--*/

View 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);
}

View 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");
}

View File

@ -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;

View File

@ -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
*/

View File

@ -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"));
}

View File

@ -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 */

View File

@ -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.

View File

@ -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
/*

View File

@ -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
/*

View File

@ -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
/*

View File

@ -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()