2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +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: Bitrot: OpenSSL API cleanups. Viktor Dukhovni. Files:
.indent.pro, tls/tls.h, tls/tls_dane.c, tls/tls_fprint.c, .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. 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 6 smtpd_starttls_timeout = ${stress?{10}:{300}}s
7 address_verify_poll_count = ${stress?{1}:{3}} 7 address_verify_poll_count = ${stress?{1}:{3}}
With Postfix versions before 3.0, replace ${stress?{x}:{y}} with ${stress?x}$ Postfix versions before 3.0 use the older form ${stress?x}${stress:y} instead
{stress:y}. of the newer form ${stress?{x}:{y}}.
Translation: Translation:
@ -149,8 +149,8 @@ Translation:
$unverified_sender_tempfail_action. No mail should be lost, as long as this $unverified_sender_tempfail_action. No mail should be lost, as long as this
measure is used only temporarily. measure is used only temporarily.
The syntax of ${name?value} and ${name:value} is explained at the beginning of The syntax of ${name?{value}:{value}}, ${name?value} and ${name:value} is
the postconf(5) manual page. explained at the beginning of the postconf(5) manual page.
NOTE: Please keep in mind that the stress-adaptive feature is a fairly NOTE: Please keep in mind that the stress-adaptive feature is a fairly
desperate measure to keep ssoommee legitimate mail flowing under overload 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> </pre>
</blockquote> </blockquote>
<p> With Postfix versions before 3.0, replace ${stress?{x}:{y}} <p> Postfix versions before 3.0 use the older form ${stress?x}${stress:y}
with ${stress?x}${stress:y}. </p> instead of the newer form ${stress?{x}:{y}}. </p>
<p> Translation: <p> <p> Translation: <p>
@ -219,8 +219,9 @@ as this measure is used only temporarily. </p>
</ul> </ul>
<p> The syntax of ${name?value} and ${name:value} is explained at <p> The syntax of ${name?{value}:{value}}, ${name?value} and
the beginning of the <a href="postconf.5.html">postconf(5)</a> manual page. </p> ${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 <p> NOTE: Please keep in mind that the stress-adaptive feature is
a fairly desperate measure to keep <b>some</b> legitimate mail 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 postqueue - Postfix queue control
<b>SYNOPSIS</b> <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>-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>-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>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> <b>DESCRIPTION</b>
The <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command implements the Postfix user interface for 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 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. 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 <b>-p</b> Produce a traditional sendmail-style queue listing. This option
implements the traditional <b>mailq</b> command, by contacting the implements the traditional <b>mailq</b> command, by contacting the
Postfix <a href="showq.8.html"><b>showq</b>(8)</a> daemon. 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 This program is designed to run with set-group ID privileges, so that
it can connect to Postfix daemon processes. 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> <b>DIAGNOSTICS</b>
Problems are logged to <b>syslogd</b>(8) and to the standard error stream. 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 P.O. Box 704
Yorktown Heights, NY 10598, USA Yorktown Heights, NY 10598, USA
Wietse Venema
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
POSTQUEUE(1) POSTQUEUE(1)
</pre> </body> </html> </pre> </body> </html>

View File

@ -13,8 +13,9 @@ SHOWQ(8) SHOWQ(8)
<b>showq</b> [generic Postfix daemon options] <b>showq</b> [generic Postfix daemon options]
<b>DESCRIPTION</b> <b>DESCRIPTION</b>
The <a href="showq.8.html"><b>showq</b>(8)</a> daemon reports the Postfix mail queue status. It is the The <a href="showq.8.html"><b>showq</b>(8)</a> daemon reports the Postfix mail queue status. The output
program that emulates the sendmail `mailq' command. 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- 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 ruser. This mode of operation is used to emulate the `mailq' command
@ -110,5 +111,10 @@ SHOWQ(8) SHOWQ(8)
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA Yorktown Heights, NY 10598, USA
Wietse Venema
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
SHOWQ(8) SHOWQ(8)
</pre> </body> </html> </pre> </body> </html>

View File

@ -158,6 +158,11 @@
# IBM T.J. Watson Research # IBM T.J. Watson Research
# P.O. Box 704 # P.O. Box 704
# Yorktown Heights, NY 10598, USA # 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. # Emit system-dependent Makefile macro definitions to standard output.

View File

@ -8,13 +8,19 @@ Postfix queue control
.SH "SYNOPSIS" .SH "SYNOPSIS"
.na .na
.nf .nf
\fBTo flush the mail queue\fR:
\fBpostqueue\fR [\fB\-v\fR] [\fB\-c \fIconfig_dir\fR] \fB\-f\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 \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 \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 .SH DESCRIPTION
.ad .ad
.fi .fi
@ -46,6 +52,48 @@ This option implements the traditional \fBsendmail \-qI\fR
command, by contacting the \fBflush\fR(8) server. command, by contacting the \fBflush\fR(8) server.
This feature is available with Postfix version 2.4 and later. 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 .IP \fB\-p\fR
Produce a traditional sendmail\-style queue listing. Produce a traditional sendmail\-style queue listing.
This option implements the traditional \fBmailq\fR command, This option implements the traditional \fBmailq\fR command,
@ -85,6 +133,10 @@ this option is available for the super\-user only.
.fi .fi
This program is designed to run with set\-group ID privileges, so This program is designed to run with set\-group ID privileges, so
that it can connect to Postfix daemon processes. that it can connect to Postfix daemon processes.
.SH "STANDARDS"
.na
.nf
RFC 7159 (JSON notation)
.SH DIAGNOSTICS .SH DIAGNOSTICS
.ad .ad
.fi .fi
@ -187,3 +239,8 @@ Wietse Venema
IBM T.J. Watson Research IBM T.J. Watson Research
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA 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 .ad
.fi .fi
The \fBshowq\fR(8) daemon reports the Postfix mail queue status. 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 The \fBshowq\fR(8) daemon can also be run in stand\-alone mode
by the superuser. This mode of operation is used to emulate by the superuser. This mode of operation is used to emulate
@ -111,3 +112,8 @@ Wietse Venema
IBM T.J. Watson Research IBM T.J. Watson Research
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA 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 # IBM T.J. Watson Research
# P.O. Box 704 # P.O. Box 704
# Yorktown Heights, NY 10598, USA # Yorktown Heights, NY 10598, USA
#
# Wietse Venema
# Google, Inc.
# 111 8th Avenue
# New York, NY 10011, USA
#-- #--
# Initialize. # Initialize.

View File

@ -168,8 +168,8 @@ default with Postfix 2.6 and later. </p>
</pre> </pre>
</blockquote> </blockquote>
<p> With Postfix versions before 3.0, replace ${stress?{x}:{y}} <p> Postfix versions before 3.0 use the older form ${stress?x}${stress:y}
with ${stress?x}${stress:y}. </p> instead of the newer form ${stress?{x}:{y}}. </p>
<p> Translation: <p> <p> Translation: <p>
@ -219,8 +219,9 @@ as this measure is used only temporarily. </p>
</ul> </ul>
<p> The syntax of ${name?value} and ${name:value} is explained at <p> The syntax of ${name?{value}:{value}}, ${name?value} and
the beginning of the postconf(5) manual page. </p> ${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 <p> NOTE: Please keep in mind that the stress-adaptive feature is
a fairly desperate measure to keep <b>some</b> legitimate mail 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 * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20151031" #define MAIL_RELEASE_DATE "20151129"
#define MAIL_VERSION_NUMBER "3.1" #define MAIL_VERSION_NUMBER "3.1"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -1,7 +1,7 @@
SHELL = /bin/sh SHELL = /bin/sh
SRCS = postqueue.c SRCS = postqueue.c showq_compat.c showq_json.c
OBJS = postqueue.o OBJS = postqueue.o showq_compat.o showq_json.o
HDRS = HDRS = postqueue.h
TESTSRC = TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS) CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@ -16,7 +16,7 @@ LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
$(PROG): $(OBJS) $(LIBS) $(PROG): $(OBJS) $(LIBS)
$(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
$(OBJS): ../../conf/makedefs.out $(OBJS): ../../conf/makedefs.out postqueue.h
Makefile: Makefile.in Makefile: Makefile.in
cat ../../conf/makedefs.out $? >$@ cat ../../conf/makedefs.out $? >$@
@ -84,6 +84,7 @@ postqueue.o: ../../include/mymalloc.h
postqueue.o: ../../include/nvtable.h postqueue.o: ../../include/nvtable.h
postqueue.o: ../../include/safe.h postqueue.o: ../../include/safe.h
postqueue.o: ../../include/smtp_stream.h postqueue.o: ../../include/smtp_stream.h
postqueue.o: ../../include/stringops.h
postqueue.o: ../../include/sys_defs.h postqueue.o: ../../include/sys_defs.h
postqueue.o: ../../include/user_acl.h postqueue.o: ../../include/user_acl.h
postqueue.o: ../../include/valid_hostname.h postqueue.o: ../../include/valid_hostname.h
@ -93,3 +94,40 @@ postqueue.o: ../../include/vstream.h
postqueue.o: ../../include/vstring.h postqueue.o: ../../include/vstring.h
postqueue.o: ../../include/warn_stat.h postqueue.o: ../../include/warn_stat.h
postqueue.o: postqueue.c 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 /* SUMMARY
/* Postfix queue control /* Postfix queue control
/* SYNOPSIS /* SYNOPSIS
/* \fBTo flush the mail queue\fR:
/*
/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-f\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 /* \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 /* \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 /* DESCRIPTION
/* The \fBpostqueue\fR(1) command implements the Postfix user interface /* The \fBpostqueue\fR(1) command implements the Postfix user interface
/* for queue management. It implements operations that are /* for queue management. It implements operations that are
@ -40,6 +46,48 @@
/* command, by contacting the \fBflush\fR(8) server. /* command, by contacting the \fBflush\fR(8) server.
/* /*
/* This feature is available with Postfix version 2.4 and later. /* 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 /* .IP \fB-p\fR
/* Produce a traditional sendmail-style queue listing. /* Produce a traditional sendmail-style queue listing.
/* This option implements the traditional \fBmailq\fR command, /* This option implements the traditional \fBmailq\fR command,
@ -77,6 +125,8 @@
/* .fi /* .fi
/* This program is designed to run with set-group ID privileges, so /* This program is designed to run with set-group ID privileges, so
/* that it can connect to Postfix daemon processes. /* that it can connect to Postfix daemon processes.
/* STANDARDS
/* RFC 7159 (JSON notation)
/* DIAGNOSTICS /* DIAGNOSTICS
/* Problems are logged to \fBsyslogd\fR(8) and to the standard error /* Problems are logged to \fBsyslogd\fR(8) and to the standard error
/* stream. /* stream.
@ -161,6 +211,11 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/ /*--*/
/* System library. */ /* System library. */
@ -188,6 +243,7 @@
#include <valid_hostname.h> #include <valid_hostname.h>
#include <warn_stat.h> #include <warn_stat.h>
#include <events.h> #include <events.h>
#include <stringops.h>
/* Global library. */ /* Global library. */
@ -208,6 +264,8 @@
/* Application-specific. */ /* Application-specific. */
#include <postqueue.h>
/* /*
* WARNING WARNING WARNING * WARNING WARNING WARNING
* *
@ -241,6 +299,7 @@
#define PQ_MODE_FLUSH_QUEUE 2 /* flush queue */ #define PQ_MODE_FLUSH_QUEUE 2 /* flush queue */
#define PQ_MODE_FLUSH_SITE 3 /* flush site */ #define PQ_MODE_FLUSH_SITE 3 /* flush site */
#define PQ_MODE_FLUSH_FILE 4 /* flush message */ #define PQ_MODE_FLUSH_FILE 4 /* flush message */
#define PQ_MODE_JSON_LIST 5 /* JSON-format queue listing */
/* /*
* Silly little macros (SLMs). * Silly little macros (SLMs).
@ -261,10 +320,9 @@ static const CONFIG_STR_TABLE str_table[] = {
/* show_queue - show queue status */ /* show_queue - show queue status */
static void show_queue(void) static void show_queue(int mode)
{ {
const char *errstr; const char *errstr;
char buf[VSTREAM_BUFSIZE];
VSTREAM *showq; VSTREAM *showq;
int n; int n;
uid_t uid = getuid(); uid_t uid = getuid();
@ -277,19 +335,20 @@ static void show_queue(void)
errstr, (long) uid); errstr, (long) uid);
/* /*
* Connect to the show queue service. Terminate silently when piping into * Connect to the show queue service.
* a program that terminates early.
*/ */
if ((showq = mail_connect(MAIL_CLASS_PUBLIC, var_showq_service, BLOCKING)) != 0) { if ((showq = mail_connect(MAIL_CLASS_PUBLIC, var_showq_service, BLOCKING)) != 0) {
while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) { switch (mode) {
if (vstream_fwrite(VSTREAM_OUT, buf, n) != n case PQ_MODE_MAILQ_LIST:
|| vstream_fflush(VSTREAM_OUT) != 0) { showq_compat(showq);
if (errno == EPIPE)
break; break;
msg_fatal("write error: %m"); case PQ_MODE_JSON_LIST:
showq_json(showq);
break;
default:
msg_panic("show_queue: unknown mode %d", mode);
} }
} if (vstream_fclose(showq))
if (vstream_fclose(showq) && errno != EPIPE)
msg_warn("close: %m"); msg_warn("close: %m");
} }
@ -308,21 +367,40 @@ static void show_queue(void)
* directly. Just run the showq program in stand-alone mode. * directly. Just run the showq program in stand-alone mode.
*/ */
else if (geteuid() == 0) { else if (geteuid() == 0) {
char *showq_path;
ARGV *argv; ARGV *argv;
int stat; int stat;
msg_warn("Mail system is down -- accessing queue directly"); 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 = 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++) for (n = 0; n < msg_verbose; n++)
argv_add(argv, "-v", (char *) 0); argv_add(argv, "-v", (char *) 0);
argv_terminate(argv); 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); argv_free(argv);
if (stat != 0) if (stat != 0)
msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE, msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE,
"Error running %s/%s", "Error running %s", showq_path);
var_daemon_dir, argv->argv[0]); 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 * mail configuration read routine. Don't do complex things until we have
* completed initializations. * completed initializations.
*/ */
while ((c = GETOPT(argc, argv, "c:fi:ps:v")) > 0) { while ((c = GETOPT(argc, argv, "c:fi:jps:v")) > 0) {
switch (c) { switch (c) {
case 'c': /* non-default configuration */ case 'c': /* non-default configuration */
if (setenv(CONF_ENV_PATH, optarg, 1) < 0) if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
@ -517,6 +595,11 @@ int main(int argc, char **argv)
mode = PQ_MODE_FLUSH_FILE; mode = PQ_MODE_FLUSH_FILE;
id_to_flush = optarg; id_to_flush = optarg;
break; break;
case 'j':
if (mode != PQ_MODE_DEFAULT)
usage();
mode = PQ_MODE_JSON_LIST;
break;
case 'p': /* traditional mailq */ case 'p': /* traditional mailq */
if (mode != PQ_MODE_DEFAULT) if (mode != PQ_MODE_DEFAULT)
usage(); usage();
@ -597,7 +680,8 @@ int main(int argc, char **argv)
msg_panic("unknown operation mode: %d", mode); msg_panic("unknown operation mode: %d", mode);
/* NOTREACHED */ /* NOTREACHED */
case PQ_MODE_MAILQ_LIST: case PQ_MODE_MAILQ_LIST:
show_queue(); case PQ_MODE_JSON_LIST:
show_queue(mode);
exit(0); exit(0);
break; break;
case PQ_MODE_FLUSH_SITE: 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] /* \fBshowq\fR [generic Postfix daemon options]
/* DESCRIPTION /* DESCRIPTION
/* The \fBshowq\fR(8) daemon reports the Postfix mail queue status. /* 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 /* The \fBshowq\fR(8) daemon can also be run in stand-alone mode
/* by the superuser. This mode of operation is used to emulate /* by the superuser. This mode of operation is used to emulate
@ -89,6 +90,11 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/ /*--*/
/* System library. */ /* System library. */
@ -140,18 +146,6 @@
int var_dup_filter_limit; int var_dup_filter_limit;
char *var_empty_addr; 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 *, static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *,
HTABLE *); HTABLE *);
@ -167,15 +161,30 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
int rec_type; int rec_type;
time_t arrival_time = 0; time_t arrival_time = 0;
char *start; char *start;
long msg_size = 0; long msg_size = size;
BOUNCE_LOG *logfile; BOUNCE_LOG *logfile;
HTABLE *dup_filter = 0; HTABLE *dup_filter = 0;
RCPT_BUF *rcpt_buf = 0; RCPT_BUF *rcpt_buf = 0;
DSN_BUF *dsn_buf = 0; DSN_BUF *dsn_buf = 0;
char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : int sender_seen = 0;
strcmp(queue, MAIL_QUEUE_HOLD) == 0 ? '!' : ' ');
int msg_size_ok = 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 * XXX addresses in defer logfiles are in printable quoted form, while
* addresses in message envelope records are in raw unquoted form. This * 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, '?')); msg_info("record %c %s", rec_type, printable(start, '?'));
switch (rec_type) { switch (rec_type) {
case REC_TYPE_TIME: case REC_TYPE_TIME:
/* TODO: parse seconds and microseconds. */
if (arrival_time == 0)
arrival_time = atol(start); arrival_time = atol(start);
break; break;
case REC_TYPE_SIZE: case REC_TYPE_SIZE:
if (msg_size == 0) { if (msg_size_ok == 0) {
if ((msg_size_ok = ((msg_size = atol(start)) > 0)) == 0) { msg_size_ok = (alldig(start) && (msg_size = atol(start)) >= 0);
msg_warn("%s: malformed size record: %.100s", if (msg_size_ok == 0) {
msg_warn("%s: malformed size record: %.100s "
"-- using file size instead",
id, printable(start, '?')); id, printable(start, '?'));
msg_size = size; msg_size = size;
} }
@ -208,25 +221,40 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
start = var_empty_addr; start = var_empty_addr;
quote_822_local(printable_quoted_addr, start); quote_822_local(printable_quoted_addr, start);
printable(STR(printable_quoted_addr), '?'); printable(STR(printable_quoted_addr), '?');
/* quote_822_local() saves buf, so we can reuse its space. */ if (sender_seen++ > 0) {
vstring_sprintf(buf, "%s%c", id, status); msg_warn("%s: duplicate sender address: %s "
vstream_fprintf(client, var_long_queue_ids ? "-- skipping remainder of this file",
L_SENDER_FORMAT : S_SENDER_FORMAT, STR(buf), id, STR(printable_quoted_addr));
msg_size > 0 ? msg_size : size, arrival_time > 0 ? SHOWQ_CLEANUP_AND_RETURN;
asctime(localtime(&arrival_time)) : }
asctime(localtime(&mtime)), attr_print(client, ATTR_FLAG_MORE,
STR(printable_quoted_addr)); 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; break;
case REC_TYPE_RCPT: 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? */ if (*start == 0) /* can't happen? */
start = var_empty_addr; start = var_empty_addr;
quote_822_local(printable_quoted_addr, start); quote_822_local(printable_quoted_addr, start);
printable(STR(printable_quoted_addr), '?'); printable(STR(printable_quoted_addr), '?');
if (dup_filter == 0 if (dup_filter == 0
|| htable_locate(dup_filter, STR(printable_quoted_addr)) == 0) || htable_locate(dup_filter, STR(printable_quoted_addr)) == 0)
vstream_fprintf(client, var_long_queue_ids ? attr_print(client, ATTR_FLAG_MORE,
L_STRING_FORMAT : S_STRING_FORMAT, SEND_ATTR_STR(MAIL_ATTR_RECIP,
"", "", "", STR(printable_quoted_addr)); STR(printable_quoted_addr)),
SEND_ATTR_STR(MAIL_ATTR_WHY, ""),
ATTR_TYPE_END);
break; break;
case REC_TYPE_MESG: case REC_TYPE_MESG:
if (msg_size_ok && vstream_fseek(qfile, msg_size, SEEK_CUR) < 0) 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 * Before listing any recipients from the queue file, try to list
* defer logfile is not necessarily complete: delivery may be * 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 * interrupted (postfix stop or reload) before all recipients have
* been tried. * been tried.
* *
* Therefore we keep a record of recipients found in the defer logfile, * Therefore we keep a record of recipients found in the defer logfile,
* and try to avoid listing those recipients again when processing * 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 if (rec_type == REC_TYPE_FROM
&& dup_filter == 0
&& (logfile = bounce_log_open(MAIL_QUEUE_DEFER, id, O_RDONLY, 0)) != 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); dup_filter = htable_create(var_dup_filter_limit);
if (rcpt_buf == 0) if (rcpt_buf == 0)
rcpt_buf = rcpb_create(); 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); msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
} }
} }
vstring_free(buf); SHOWQ_CLEANUP_AND_RETURN;
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_reasons - show deferral reasons */ /* 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, static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
DSN_BUF *dsn_buf, HTABLE *dup_filter) DSN_BUF *dsn_buf, HTABLE *dup_filter)
{ {
char *saved_reason = 0;
int padding;
RECIPIENT *rcpt = &rcpt_buf->rcpt; RECIPIENT *rcpt = &rcpt_buf->rcpt;
DSN *dsn = &dsn_buf->dsn; 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) if (htable_locate(dup_filter, rcpt->address) == 0)
htable_enter(dup_filter, rcpt->address, (void *) 0); htable_enter(dup_filter, rcpt->address, (void *) 0);
/* attr_print(client, ATTR_FLAG_MORE,
* Don't print the reason when the previous recipient had the same SEND_ATTR_STR(MAIL_ATTR_RECIP, rcpt->address),
* problem. SEND_ATTR_STR(MAIL_ATTR_WHY, dsn->reason),
*/ ATTR_TYPE_END);
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);
}
if (saved_reason)
myfree(saved_reason);
} }
@ -318,7 +329,6 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
int status; int status;
char *id; char *id;
int file_count; int file_count;
unsigned long queue_size = 0;
struct stat st; struct stat st;
struct queue_info { struct queue_info {
char *name; /* queue name */ char *name; /* queue name */
@ -368,30 +378,14 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
saved_id = mystrdup(id); saved_id = mystrdup(id);
status = mail_open_ok(qp->name, id, &st, &path); status = mail_open_ok(qp->name, id, &st, &path);
if (status == MAIL_OPEN_YES) { 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) { 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, showq_report(client, qp->name, id, qfile, (long) st.st_size,
st.st_mtime); st.st_mtime);
if (vstream_fclose(qfile)) if (vstream_fclose(qfile))
msg_warn("close file %s %s: %m", qp->name, id); msg_warn("close file %s %s: %m", qp->name, id);
} else if (strcmp(qp->name, MAIL_QUEUE_MAILDROP) == 0) { } else if (errno != ENOENT) {
queue_size += st.st_size; msg_warn("open %s %s: %m", qp->name, id);
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);
} }
vstream_fflush(client); vstream_fflush(client);
} }
@ -399,13 +393,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
myfree(saved_id); myfree(saved_id);
scan_dir_close(scan); scan_dir_close(scan);
} }
if (file_count == 0) attr_print(client, ATTR_FLAG_NONE, ATTR_TYPE_END);
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");
}
} }
MAIL_VERSION_STAMP_DECLARE; MAIL_VERSION_STAMP_DECLARE;

View File

@ -567,16 +567,21 @@ extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *);
/* /*
* smtp_trouble.c * smtp_trouble.c
*/ */
#define SMTP_THROTTLE 1
#define SMTP_NOTHROTTLE 0
extern int smtp_sess_fail(SMTP_STATE *); extern int smtp_sess_fail(SMTP_STATE *);
extern int PRINTFLIKE(4, 5) smtp_site_fail(SMTP_STATE *, const char *, extern int PRINTFLIKE(5, 6) smtp_misc_fail(SMTP_STATE *, int, const char *,
SMTP_RESP *, const char *,...);
extern int PRINTFLIKE(4, 5) smtp_mesg_fail(SMTP_STATE *, const char *,
SMTP_RESP *, const char *,...); SMTP_RESP *, const char *,...);
extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *, extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *,
const char *, SMTP_RESP *, const char *, SMTP_RESP *,
const char *,...); const char *,...);
extern int smtp_stream_except(SMTP_STATE *, int, 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 * 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 * authentication. If the server doesn't announce SASL support over
* plaintext connections, then we don't want delivery to fail with * plaintext connections, then we don't want delivery to fail with
* "relay access denied". * "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) if (PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE)
RETRY_AS_PLAINTEXT; 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"), SMTP_RESP_FAKE(&fake, "4.7.5"),
"Cannot start TLS: handshake failure")); "Cannot start TLS: handshake failure"));
} }

View File

@ -32,6 +32,13 @@
/* SMTP_STATE *state; /* SMTP_STATE *state;
/* int exception; /* int exception;
/* const char *description; /* 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 /* DESCRIPTION
/* This module handles all non-fatal errors that can happen while /* This module handles all non-fatal errors that can happen while
/* attempting to deliver mail via SMTP, and implements the policy /* attempting to deliver mail via SMTP, and implements the policy
@ -82,6 +89,13 @@
/* remaining recipients. /* remaining recipients.
/* The result is non-zero. /* 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 /* smtp_rcpt_fail() handles the case where a recipient is not
/* accepted by the server for reasons other than that the server /* accepted by the server for reasons other than that the server
/* recipient limit is reached. /* recipient limit is reached.
@ -162,9 +176,6 @@
#include "smtp.h" #include "smtp.h"
#include "smtp_sasl.h" #include "smtp_sasl.h"
#define SMTP_THROTTLE 1
#define SMTP_NOTHROTTLE 0
/* smtp_check_code - check response code */ /* smtp_check_code - check response code */
static void smtp_check_code(SMTP_SESSION *session, int 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); 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, int smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
const char *format,...) SMTP_RESP *resp, const char *format,...)
{ {
va_list ap; 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. * Skip, defer or bounce recipients, and throttle this queue.
*/ */
return (smtp_bulk_fail(state, SMTP_THROTTLE)); return (smtp_bulk_fail(state, 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));
} }
/* smtp_rcpt_fail - skip, defer, or bounce recipient */ /* 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_vprint attr_vprint0
#define attr_scan attr_scan0 #define attr_scan attr_scan0
#define attr_vscan attr_vscan0 #define attr_vscan attr_vscan0
#define attr_scan_more attr_scan_more0
/* /*
* attr_print64.c. * 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_scan64(VSTREAM *, int,...);
extern int WARN_UNUSED_RESULT attr_vscan64(VSTREAM *, int, va_list); extern int WARN_UNUSED_RESULT attr_vscan64(VSTREAM *, int, va_list);
extern int WARN_UNUSED_RESULT attr_scan_more64(VSTREAM *);
/* /*
* attr_print0.c. * 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_scan0(VSTREAM *, int,...);
extern int WARN_UNUSED_RESULT attr_vscan0(VSTREAM *, int, va_list); extern int WARN_UNUSED_RESULT attr_vscan0(VSTREAM *, int, va_list);
extern int WARN_UNUSED_RESULT attr_scan_more0(VSTREAM *);
/* /*
* attr_scan_plain.c. * attr_scan_plain.c.
*/ */
extern int attr_print_plain(VSTREAM *, int,...); extern int attr_print_plain(VSTREAM *, int,...);
extern int attr_vprint_plain(VSTREAM *, int, va_list); extern int attr_vprint_plain(VSTREAM *, int, va_list);
extern int attr_scan_more_plain(VSTREAM *);
/* /*
* attr_print_plain.c. * 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_scan_plain(VSTREAM *, int,...);
extern int WARN_UNUSED_RESULT attr_vscan_plain(VSTREAM *, int, va_list); extern int WARN_UNUSED_RESULT attr_vscan_plain(VSTREAM *, int, va_list);
/* /*
* Attribute names for testing the compatibility of the read and write * Attribute names for testing the compatibility of the read and write
* routines. * routines.

View File

@ -7,15 +7,18 @@
/* #include <attr.h> /* #include <attr.h>
/* /*
/* int attr_scan0(fp, flags, type, name, ..., ATTR_TYPE_END) /* int attr_scan0(fp, flags, type, name, ..., ATTR_TYPE_END)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* int type; /* int type;
/* char *name; /* char *name;
/* /*
/* int attr_vscan0(fp, flags, ap) /* int attr_vscan0(fp, flags, ap)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* va_list ap; /* va_list ap;
/*
/* int attr_scan_more0(fp)
/* VSTREAM *fp;
/* DESCRIPTION /* DESCRIPTION
/* attr_scan0() takes zero or more (name, value) request attributes /* attr_scan0() takes zero or more (name, value) request attributes
/* and recovers the attribute values from the byte stream that was /* and recovers the attribute values from the byte stream that was
@ -24,6 +27,11 @@
/* attr_vscan0() provides an alternative interface that is convenient /* attr_vscan0() provides an alternative interface that is convenient
/* for calling from within a variadic function. /* 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 /* The input stream is formatted as follows, where (item)* stands
/* for zero or more instances of the specified item, and where /* for zero or more instances of the specified item, and where
/* (item1 | item2) stands for choice: /* (item1 | item2) stands for choice:
@ -144,6 +152,11 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/ /*--*/
/* System library. */ /* System library. */
@ -450,6 +463,30 @@ int attr_scan0(VSTREAM *fp, int flags,...)
return (ret); 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 #ifdef TEST
/* /*

View File

@ -7,15 +7,18 @@
/* #include <attr.h> /* #include <attr.h>
/* /*
/* int attr_scan64(fp, flags, type, name, ..., ATTR_TYPE_END) /* int attr_scan64(fp, flags, type, name, ..., ATTR_TYPE_END)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* int type; /* int type;
/* char *name; /* char *name;
/* /*
/* int attr_vscan64(fp, flags, ap) /* int attr_vscan64(fp, flags, ap)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* va_list ap; /* va_list ap;
/*
/* int attr_scan_more64(fp)
/* VSTREAM *fp;
/* DESCRIPTION /* DESCRIPTION
/* attr_scan64() takes zero or more (name, value) request attributes /* attr_scan64() takes zero or more (name, value) request attributes
/* and recovers the attribute values from the byte stream that was /* and recovers the attribute values from the byte stream that was
@ -24,6 +27,11 @@
/* attr_vscan64() provides an alternative interface that is convenient /* attr_vscan64() provides an alternative interface that is convenient
/* for calling from within a variadic function. /* 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 /* The input stream is formatted as follows, where (item)* stands
/* for zero or more instances of the specified item, and where /* for zero or more instances of the specified item, and where
/* (item1 | item2) stands for choice: /* (item1 | item2) stands for choice:
@ -146,6 +154,11 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/ /*--*/
/* System library. */ /* System library. */
@ -509,6 +522,30 @@ int attr_scan64(VSTREAM *fp, int flags,...)
return (ret); 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 #ifdef TEST
/* /*

View File

@ -7,15 +7,18 @@
/* #include <attr.h> /* #include <attr.h>
/* /*
/* int attr_scan_plain(fp, flags, type, name, ..., ATTR_TYPE_END) /* int attr_scan_plain(fp, flags, type, name, ..., ATTR_TYPE_END)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* int type; /* int type;
/* char *name; /* char *name;
/* /*
/* int attr_vscan_plain(fp, flags, ap) /* int attr_vscan_plain(fp, flags, ap)
/* VSTREAM fp; /* VSTREAM *fp;
/* int flags; /* int flags;
/* va_list ap; /* va_list ap;
/*
/* int attr_scan_more_plain(fp)
/* VSTREAM *fp;
/* DESCRIPTION /* DESCRIPTION
/* attr_scan_plain() takes zero or more (name, value) request attributes /* attr_scan_plain() takes zero or more (name, value) request attributes
/* and recovers the attribute values from the byte stream that was /* 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 /* attr_vscan_plain() provides an alternative interface that is convenient
/* for calling from within a variadic function. /* 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 /* The input stream is formatted as follows, where (item)* stands
/* for zero or more instances of the specified item, and where /* for zero or more instances of the specified item, and where
/* (item1 | item2) stands for choice: /* (item1 | item2) stands for choice:
@ -144,6 +152,11 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/ /*--*/
/* System library. */ /* System library. */
@ -492,6 +505,30 @@ int attr_scan_plain(VSTREAM *fp, int flags,...)
return (ret); 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 #ifdef TEST
/* /*

View File

@ -399,7 +399,8 @@
/* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND). /* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND).
/* /*
/* vstream_peek_data() returns a pointer to the unread bytes /* 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 /* vstream_setjmp() saves processing context and makes that context
/* available for use with vstream_longjmp(). Normally, vstream_setjmp() /* available for use with vstream_longjmp(). Normally, vstream_setjmp()