mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
postfix-2.12-20140921
This commit is contained in:
parent
558905a662
commit
098feb387e
3
postfix/.indent.pro
vendored
3
postfix/.indent.pro
vendored
@ -168,7 +168,8 @@
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TLONG_NAME_MASK
|
||||
-TMAC_EXP
|
||||
-TMAC_EXP_CONTEXT
|
||||
-TMAC_EXP_OP_INFO
|
||||
-TMAC_HEAD
|
||||
-TMAC_PARSE
|
||||
-TMAIL_PRINT
|
||||
|
@ -20345,3 +20345,68 @@ Apologies for any names omitted.
|
||||
global/deliver_request.h, global/mail_params.h, global/sent.c,
|
||||
*qmgr/qmgr.c, *qmgr/qmgr_active.c, *qmgr/qmgr_message.c.
|
||||
|
||||
20140908-14
|
||||
|
||||
Feature: for the first time in 17 years, support for
|
||||
${name?if-nonempty:if-empty} macro expressions, and for
|
||||
logical expressions ${logical-expr?if-true:if-false}. In
|
||||
preparation for configurable message headers and logging.
|
||||
Files: util/mac_expand.c.
|
||||
|
||||
20140914
|
||||
|
||||
Bugfix (introduced: 19971026): a zero precision value in
|
||||
%.*s and $.<digits>s was implemented as if no precision
|
||||
value was specified, i.e. print the entire string. This was
|
||||
not harmful, it just looked weird. File: util/vbuf_print.c.
|
||||
|
||||
20120917
|
||||
|
||||
Feature: RFC 7372 enhanced status code for unknown SMTP
|
||||
client hostnames. File: smtpd/smtpd_check.c
|
||||
|
||||
Bugfix: the accept() calls in test progams escaped attention
|
||||
when Postfix 2.2 was ported to IPv6. Problem found by Mark
|
||||
Martinec. Files: smtpstone/smtp-sink.c, smtpstone/qmqp-sink.c.
|
||||
|
||||
20140918
|
||||
|
||||
Cleanup: log a warning when the cleanup server detects too
|
||||
many hops. smtpd(8) does not log any of the CLEANUP_STAT_XXX
|
||||
results. The pickup server logs some because there is no
|
||||
client to send the problem description to. This logic of
|
||||
who logs what needs to be revisited. File:
|
||||
cleanup/cleanup_message.c.
|
||||
|
||||
20140919
|
||||
|
||||
Usability: randmap and pipemap syntax, for example,
|
||||
pipemap:{type_1:name_1, ..., type_n:name_n}. This required
|
||||
small updates to code that parses input into lookup table
|
||||
names. Files: global/data_redirect.c, global/maps.c,
|
||||
global/server_acl.c, postconf/postconf.c, postconf/postconf_dbms.c,
|
||||
postconf/test58.ref, proto/DATABASE_README.html,
|
||||
proxymap/proxymap.c, smtpd/smtpd_check.c, util/argv.h,
|
||||
util/balpar.c, util/dict_pipe.c, util/dict_random.c,
|
||||
util/match_list.c, util/mystrtok.c, util/argv_splitq.c,
|
||||
util/stringops.h.
|
||||
|
||||
Cleanup: added PRINTFLIKE() to enable missing format string
|
||||
checks. Files: bounce/bounce_template.h, global/memcache_proto.h,
|
||||
global/dict_memcache, postconf/postconf.h, util/dict.h,
|
||||
util/msg.h.
|
||||
|
||||
20140920
|
||||
|
||||
Bugfix (introduced: 20080212): incorrect client name in
|
||||
reject messages from check_reverse_client_hostname_access
|
||||
and check_reverse_client_hostname_{a,mx,ns}_access. They
|
||||
replied with the verified client name, instead of the name
|
||||
that was rejected. Problem reported by Reindl Harald. File:
|
||||
smtpd/smtpd_check.c.
|
||||
|
||||
20140921
|
||||
|
||||
Cleanup: postconf code to determine the default mydomain
|
||||
value had not evolved since 1997, while the rest of Postfix
|
||||
changed in 2000. File: postconf/postconf-dbms.c.
|
||||
|
@ -243,13 +243,13 @@ To find out what database types your Postfix system supports, use the "ppooss
|
||||
format is described in pcre_table(5). The lookup table name as used in
|
||||
"pcre:table" is the name of the regular expression file.
|
||||
ppiippeemmaapp (read-only)
|
||||
A pipeline of lookup tables. Example: "ppiippeemmaapp::!type1:name1! ...
|
||||
!typen:namen". Each "pipemap:" query is given to the first table. Each
|
||||
A pipeline of lookup tables. Example: "pipemap:{type1:name1, ...,
|
||||
typen:namen}". Each "pipemap:" query is given to the first table. Each
|
||||
lookup result becomes the query for the next table in the pipeline, and
|
||||
the last table produces the final result. When any table lookup
|
||||
produces no result, the pipeline produces no result. The first ASCII
|
||||
character after "pipemap:" will be used as the separator between the
|
||||
lookup tables that follow (do not use space, ",", ":" or non-ASCII).
|
||||
produces no result, the pipeline produces no result. The first and last
|
||||
characters of the "pipemap:" table name must be "{" and "}". Within
|
||||
these, individual maps are separated with comma or whitespace.
|
||||
ppggssqqll (read-only)
|
||||
PostgreSQL database client. Configuration details are given in
|
||||
pgsql_table(5).
|
||||
@ -257,11 +257,11 @@ To find out what database types your Postfix system supports, use the "ppooss
|
||||
Postfix proxymap(8) client for shared access to Postfix databases. The
|
||||
lookup table name syntax is "proxy:type:table".
|
||||
rraannddmmaapp (read-only)
|
||||
An in-memory table that performs random selection. Example: "rraannddmmaapp::
|
||||
!result1! ... !resultn". Each table query returns a random choice from
|
||||
the specified results. The first ASCII character after "randmap:" will
|
||||
be used as the separator between the results that follow (do not use
|
||||
space, ",", ":" or non-ASCII).
|
||||
An in-memory table that performs random selection. Example: "randmap:
|
||||
{result1. ..., resultn}". Each table query returns a random choice from
|
||||
the specified results. The first and last characters of the "randmap:
|
||||
" table name must be "{" and "}". Within these, individual maps are
|
||||
separated with comma or whitespace.
|
||||
rreeggeexxpp (read-only)
|
||||
A lookup table based on regular expressions. The file format is
|
||||
described in regexp_table(5). The lookup table name as used in "regexp:
|
||||
|
@ -41,6 +41,36 @@ Maintainers may also benefit from the makedefs documentation
|
||||
(mantools/srctoman - makedefs | nroff -man | less) with information
|
||||
about build options that are not described in the INSTALL instructions.
|
||||
|
||||
Major changes with snapshot 20140921
|
||||
====================================
|
||||
|
||||
In preparation for configurable mail headers and logging, new main.cf
|
||||
support for if-then-else expressions:
|
||||
|
||||
${name?{text1}:{text2}}
|
||||
|
||||
and for logical expressions:
|
||||
|
||||
${{text1}=={text2}?{text3}:{text4}}
|
||||
${{text1}!={text2}?{text3}:{text4}}
|
||||
|
||||
Whitespace before and after {text} is ignored. This can help to
|
||||
make complex expressions more readable. See the postconf(5) manpage
|
||||
for further details.
|
||||
|
||||
The syntax of pipemap and randmap has improved. Postfix now uses
|
||||
pipemap:{map1, ..., mapN} and randmap:{result1, ..., resultN}.
|
||||
The old syntax was just too ugly.
|
||||
|
||||
It is expected that usability can be improved elsewhere in Postfix
|
||||
in a similar manner. For example,
|
||||
|
||||
- Milter clients and policy clients with non-default settings:
|
||||
smtpd_milters = {inet:host:port, timeout=xxx, default_action=yyy}, ...
|
||||
|
||||
- Parameter overrides in master.cf with commas and spaces:
|
||||
-o { parameter = value ... }
|
||||
|
||||
Major changes with snapshot 20140801
|
||||
====================================
|
||||
|
||||
|
@ -8,8 +8,41 @@ Wish list:
|
||||
|
||||
Things to do after the stable release:
|
||||
|
||||
The pickup daemon logs warnings only when the cleanup daemon
|
||||
dit not provide a "reason" attribute. Is this logic right?
|
||||
|
||||
Make the "relayed after delay" notification conditional on
|
||||
the presence of the DSN_NOTIFY_DELAY flag.
|
||||
|
||||
up-convert myhostname to UTF-8 in MIME boundary strings?
|
||||
|
||||
Update postconf to recursively parse legacy-style mapnames
|
||||
in random:, pipe:, and other multimaps.
|
||||
|
||||
Introduce constants to replace all the ad-hoc ", \t\r\n"
|
||||
etc. for tokenization. That will have to go into an "util"
|
||||
file because match_strings(3), dict_pipe(3) and dict_random(3)
|
||||
depend on these definitions.
|
||||
|
||||
Make sure that proxy: can handle random:, pipe:, and other
|
||||
multimaps.
|
||||
|
||||
Add a switch to consider postscreen deep protocol tests as
|
||||
"completed" when receiving "RSET" after "RCPT TO" and the
|
||||
session has passed all tests up to that point. RSET becomes
|
||||
like QUIT except perhaps that it does not hang up.
|
||||
|
||||
apipe: map, splits results into address lists and performs
|
||||
lookups for the invidual addresses, converting back and
|
||||
forth between external and internal forms.
|
||||
|
||||
union: map, concatenates results, default separator is ','.
|
||||
|
||||
Include <3htPpS5B6bzbcpM@spike.porcupine.org> example with
|
||||
filter policies for different mail streams. Correction:
|
||||
filter should be content_filter. Posted Wed, 10 Sep 2014
|
||||
09:53:52 -0400 (EDT).
|
||||
|
||||
Clarify that receive_override_options should not be used
|
||||
with smtpd_proxy_filter.
|
||||
|
||||
|
@ -365,14 +365,14 @@ file. </dd>
|
||||
<dt> <b>pipemap</b> (read-only) </dt>
|
||||
|
||||
<dd> A pipeline of lookup tables. Example:
|
||||
"<b><a href="DATABASE_README.html#types">pipemap</a>:</b><i>!type<sub>1</sub>:name<sub>1</sub>! ...
|
||||
!type<sub>n</sub>:name<sub>n</sub></i>". Each "<a href="DATABASE_README.html#types">pipemap</a>:" query is
|
||||
"<a href="DATABASE_README.html#types">pipemap</a>:{<i>type<sub>1</sub>:name<sub>1</sub>, ...,
|
||||
type<sub>n</sub>:name<sub>n</sub></i>}". Each "<a href="DATABASE_README.html#types">pipemap</a>:" query is
|
||||
given to the first table. Each lookup result becomes the query for
|
||||
the next table in the pipeline, and the last table produces the
|
||||
final result. When any table lookup produces no result, the pipeline
|
||||
produces no result. The first ASCII character after "<a href="DATABASE_README.html#types">pipemap</a>:"
|
||||
will be used as the separator between the lookup tables that follow
|
||||
(do not use space, ",", ":" or non-ASCII). </dd>
|
||||
produces no result. The first and last characters of the "<a href="DATABASE_README.html#types">pipemap</a>:"
|
||||
table name must be "{" and "}". Within these, individual maps are
|
||||
separated with comma or whitespace. </dd>
|
||||
|
||||
<dt> <b>pgsql</b> (read-only) </dt>
|
||||
|
||||
@ -388,11 +388,11 @@ databases. The lookup table name syntax is "<a href="proxymap.8.html">proxy</a>:
|
||||
<dt> <b>randmap</b> (read-only) </dt>
|
||||
|
||||
<dd> An in-memory table that performs random selection. Example:
|
||||
"<b><a href="DATABASE_README.html#types">randmap</a>:</b><i>!result<sub>1</sub>! ... !result<sub>n</sub></i>".
|
||||
"<a href="DATABASE_README.html#types">randmap</a>:{<i>result<sub>1</sub>. ..., result<sub>n</sub></i>}".
|
||||
Each table query returns a random choice from the specified results.
|
||||
The first ASCII character after "<a href="DATABASE_README.html#types">randmap</a>:" will be used as the
|
||||
separator between the results that follow (do not use space, ",",
|
||||
":" or non-ASCII). </dd>
|
||||
The first and last characters of the "<a href="DATABASE_README.html#types">randmap</a>:" table name must be
|
||||
"{" and "}". Within these, individual maps are separated with comma
|
||||
or whitespace. </dd>
|
||||
|
||||
<dt> <b>regexp</b> (read-only) </dt>
|
||||
|
||||
|
@ -55,16 +55,16 @@ POSTCONF(1) POSTCONF(1)
|
||||
<b>postconf -a</b>|<b>-A</b>|<b>-l</b>|<b>-m</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>]
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
By default, the <a href="postconf.1.html"><b>postconf</b>(1)</a> command displays the values of <a href="postconf.5.html"><b>main.cf</b></a> con-
|
||||
By default, the <a href="postconf.1.html"><b>postconf</b>(1)</a> command displays the values of <a href="postconf.5.html"><b>main.cf</b></a> con‐
|
||||
figuration parameters, and warns about possible mis-typed parameter
|
||||
names (Postfix 2.9 and later). It can also change <a href="postconf.5.html"><b>main.cf</b></a> configura-
|
||||
names (Postfix 2.9 and later). It can also change <a href="postconf.5.html"><b>main.cf</b></a> configura‐
|
||||
tion parameter values, or display other configuration information about
|
||||
the Postfix mail system.
|
||||
|
||||
Options:
|
||||
|
||||
<b>-a</b> List the available SASL server plug-in types. The SASL plug-in
|
||||
type is selected with the <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b> configuration parame-
|
||||
type is selected with the <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b> configuration parame‐
|
||||
ter by specifying one of the names listed below.
|
||||
|
||||
<b>cyrus</b> This server plug-in is available when Postfix is built
|
||||
@ -78,7 +78,7 @@ POSTCONF(1) POSTCONF(1)
|
||||
This feature is available with Postfix 2.3 and later.
|
||||
|
||||
<b>-A</b> List the available SASL client plug-in types. The SASL plug-in
|
||||
type is selected with the <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b> or <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b> con-
|
||||
type is selected with the <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b> or <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b> con‐
|
||||
figuration parameters by specifying one of the names listed
|
||||
below.
|
||||
|
||||
@ -88,8 +88,8 @@ POSTCONF(1) POSTCONF(1)
|
||||
This feature is available with Postfix 2.3 and later.
|
||||
|
||||
<b>-b</b> [<i>template</i><b>_</b><i>file</i>]
|
||||
Display the message text that appears at the beginning of deliv-
|
||||
ery status notification (DSN) messages, replacing $<b>name</b> expres-
|
||||
Display the message text that appears at the beginning of deliv‐
|
||||
ery status notification (DSN) messages, replacing $<b>name</b> expres‐
|
||||
sions with actual values as described in <a href="bounce.5.html"><b>bounce</b>(5)</a>.
|
||||
|
||||
To override the built-in templates, specify a template file name
|
||||
@ -125,29 +125,29 @@ POSTCONF(1) POSTCONF(1)
|
||||
|
||||
This feature is available with Postfix 2.9 and later.
|
||||
|
||||
<b>-d</b> Print <a href="postconf.5.html"><b>main.cf</b></a> default parameter settings instead of actual set-
|
||||
<b>-d</b> Print <a href="postconf.5.html"><b>main.cf</b></a> default parameter settings instead of actual set‐
|
||||
tings. Specify <b>-df</b> to fold long lines for human readability
|
||||
(Postfix 2.9 and later).
|
||||
|
||||
<b>-e</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and update parameter set-
|
||||
<b>-e</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and update parameter set‐
|
||||
tings with the "<i>name=value</i>" pairs on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
|
||||
line.
|
||||
|
||||
With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and replace one
|
||||
or more service entries with new values as specified with "<i>ser-</i>
|
||||
or more service entries with new values as specified with "<i>ser‐</i>
|
||||
<i>vice/type=value</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
With <b>-F</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and replace one
|
||||
or more service fields with new values as specied with "<i>ser-</i>
|
||||
<i>vice/type/field=value</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. Cur-
|
||||
rently, the "command" field contains the command name and com-
|
||||
or more service fields with new values as specied with "<i>ser‐</i>
|
||||
<i>vice/type/field=value</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. Cur‐
|
||||
rently, the "command" field contains the command name and com‐
|
||||
mand arguments. this may change in the near future, so that the
|
||||
"command" field contains only the command name, and a new "argu-
|
||||
"command" field contains only the command name, and a new "argu‐
|
||||
ments" pseudofield contains the command arguments.
|
||||
|
||||
With <b>-P</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and add or
|
||||
update one or more service parameter settings (-o parame-
|
||||
ter=value settings) with new values as specied with "<i>ser-</i>
|
||||
update one or more service parameter settings (-o parame‐
|
||||
ter=value settings) with new values as specied with "<i>ser‐</i>
|
||||
<i>vice/type/parameter=value</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
In all cases the file is copied to a temporary file then renamed
|
||||
@ -166,8 +166,8 @@ POSTCONF(1) POSTCONF(1)
|
||||
and all fields), formatted as one "<i>service/type/field=value</i>" per
|
||||
line. Specify <b>-Ff</b> to fold long lines.
|
||||
|
||||
Specify one or more "<i>service/type/field</i>" instances on the <a href="postconf.1.html"><b>post-</b></a>
|
||||
<a href="postconf.1.html"><b>conf</b>(1)</a> command line to limit the output to fields of interest.
|
||||
Specify one or more "<i>service/type/field</i>" instances on the <b>post</b>‐‐
|
||||
<b>conf</b>(1) command line to limit the output to fields of interest.
|
||||
Trailing parameter name or service type fields that are omitted
|
||||
will be handled as "*" wildcard fields.
|
||||
|
||||
@ -176,7 +176,7 @@ POSTCONF(1) POSTCONF(1)
|
||||
<b>-h</b> Show parameter or attribute values without the "<i>name</i> = " label
|
||||
that normally precedes the value.
|
||||
|
||||
<b>-l</b> List the names of all supported mailbox locking methods. Post-
|
||||
<b>-l</b> List the names of all supported mailbox locking methods. Post‐
|
||||
fix supports the following methods:
|
||||
|
||||
<b>flock</b> A kernel-based advisory locking method for local files
|
||||
@ -188,21 +188,21 @@ POSTCONF(1) POSTCONF(1)
|
||||
|
||||
<b>dotlock</b>
|
||||
An application-level locking method. An application locks
|
||||
a file named <i>filename</i> by creating a file named <i>file-</i>
|
||||
a file named <i>filename</i> by creating a file named <i>file‐</i>
|
||||
<i>name</i><b>.lock</b>. The application is expected to remove its own
|
||||
lock file, as well as stale lock files that were left
|
||||
behind after abnormal program termination.
|
||||
|
||||
<b>-m</b> List the names of all supported lookup table types. In Postfix
|
||||
configuration files, lookup tables are specified as <i>type</i><b>:</b><i>name</i>,
|
||||
where <i>type</i> is one of the types listed below. The table <i>name</i> syn-
|
||||
tax depends on the lookup table type as described in the <a href="DATABASE_README.html">DATA</a>-
|
||||
<a href="DATABASE_README.html">BASE_README</a> document.
|
||||
where <i>type</i> is one of the types listed below. The table <i>name</i> syn‐
|
||||
tax depends on the lookup table type as described in the DATA‐
|
||||
<a href="BASE_README.html">BASE_README</a> document.
|
||||
|
||||
<b>btree</b> A sorted, balanced tree structure. Available on systems
|
||||
with support for Berkeley DB databases.
|
||||
|
||||
<b>cdb</b> A read-optimized structure with no support for incremen-
|
||||
<b>cdb</b> A read-optimized structure with no support for incremen‐
|
||||
tal updates. Available on systems with support for CDB
|
||||
databases.
|
||||
|
||||
@ -210,19 +210,19 @@ POSTCONF(1) POSTCONF(1)
|
||||
Domain Routing (CIDR) patterns. This is described in
|
||||
<a href="cidr_table.5.html"><b>cidr_table</b>(5)</a>.
|
||||
|
||||
<b>dbm</b> An indexed file type based on hashing. Available on sys-
|
||||
<b>dbm</b> An indexed file type based on hashing. Available on sys‐
|
||||
tems with support for DBM databases.
|
||||
|
||||
<b>environ</b>
|
||||
The UNIX process environment array. The lookup key is the
|
||||
variable name. Originally implemented for testing, some-
|
||||
variable name. Originally implemented for testing, some‐
|
||||
one may find this useful someday.
|
||||
|
||||
<b>fail</b> A table that reliably fails all requests. The lookup ta-
|
||||
ble name is used for logging. This table exists to sim-
|
||||
<b>fail</b> A table that reliably fails all requests. The lookup ta‐
|
||||
ble name is used for logging. This table exists to sim‐
|
||||
plify Postfix error tests.
|
||||
|
||||
<b>hash</b> An indexed file type based on hashing. Available on sys-
|
||||
<b>hash</b> An indexed file type based on hashing. Available on sys‐
|
||||
tems with support for Berkeley DB databases.
|
||||
|
||||
<b>internal</b>
|
||||
@ -230,23 +230,23 @@ POSTCONF(1) POSTCONF(1)
|
||||
when a process terminates.
|
||||
|
||||
<b>lmdb</b> OpenLDAP LMDB database (a memory-mapped, persistent
|
||||
file). Available on systems with support for LMDB data-
|
||||
file). Available on systems with support for LMDB data‐
|
||||
bases. This is described in <a href="lmdb_table.5.html"><b>lmdb_table</b>(5)</a>.
|
||||
|
||||
<b>ldap</b> (read-only)
|
||||
LDAP database client. This is described in <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
|
||||
|
||||
<b>memcache</b>
|
||||
Memcache database client. This is described in <a href="memcache_table.5.html"><b>mem-</b></a>
|
||||
<a href="memcache_table.5.html"><b>cache_table</b>(5)</a>.
|
||||
Memcache database client. This is described in <b>mem</b>‐‐
|
||||
<b>cache_table</b>(5).
|
||||
|
||||
<b>mysql</b> (read-only)
|
||||
MySQL database client. Available on systems with support
|
||||
for MySQL databases. This is described in <a href="mysql_table.5.html"><b>mysql_ta-</b></a>
|
||||
<a href="mysql_table.5.html"><b>ble</b>(5)</a>.
|
||||
for MySQL databases. This is described in <b>mysql_ta</b>‐‐
|
||||
<b>ble</b>(5).
|
||||
|
||||
<b>pcre</b> (read-only)
|
||||
A lookup table based on Perl Compatible Regular Expres-
|
||||
A lookup table based on Perl Compatible Regular Expres‐
|
||||
sions. The file format is described in <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
|
||||
|
||||
<b>pgsql</b> (read-only)
|
||||
@ -254,95 +254,94 @@ POSTCONF(1) POSTCONF(1)
|
||||
<a href="pgsql_table.5.html"><b>pgsql_table</b>(5)</a>.
|
||||
|
||||
<b>pipemap</b> (read-only)
|
||||
A pipeline of lookup tables. Example:
|
||||
"<b><a href="DATABASE_README.html#types">pipemap</a>:</b><i>!type</i><b>_</b><i>1:name</i><b>_</b><i>1! ... !type</i><b>_</b><i>n:name</i><b>_</b><i>n</i>". Each
|
||||
"<a href="DATABASE_README.html#types">pipemap</a>:" query is given to the first table. Each
|
||||
A lookup table that constructs a pipeline of tables.
|
||||
Example: "<b><a href="DATABASE_README.html#types">pipemap</a>:{</b><i>type</i><b>_</b><i>1:name</i><b>_</b><i>1, ..., type</i><b>_</b><i>n:name</i><b>_</b><i>n</i><b>}</b>".
|
||||
Each "<a href="DATABASE_README.html#types">pipemap</a>:" query is given to the first table. Each
|
||||
lookup result becomes the query for the next table in the
|
||||
pipeline, and the last table produces the final result.
|
||||
When any table lookup produces no result, the pipeline
|
||||
produces no result. The first ASCII character after
|
||||
"<a href="DATABASE_README.html#types">pipemap</a>:" will be used as the separator between the
|
||||
lookup tables that follow (do not use space, ",", ":" or
|
||||
non-ASCII).
|
||||
produces no result. The first and last characters of the
|
||||
"<a href="DATABASE_README.html#types">pipemap</a>:" table name must be "<b>{</b>" and "<b>}</b>". Within these,
|
||||
individual maps are separated with comma or whitespace.
|
||||
|
||||
<b>proxy</b> Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> client for shared access to Postfix
|
||||
<b>proxy</b> Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> client for shared access to Postfix
|
||||
databases. The table name syntax is <i>type</i><b>:</b><i>name</i>.
|
||||
|
||||
<b>randmap</b> (read-only)
|
||||
An in-memory table that performs random selection. Exam-
|
||||
ple: "<b><a href="DATABASE_README.html#types">randmap</a>:</b><i>!result</i><b>_</b><i>1! ... !result</i><b>_</b><i>n</i>". Each table query
|
||||
returns a random choice from the specified results. The
|
||||
first ASCII character after "<a href="DATABASE_README.html#types">randmap</a>:" will be used as
|
||||
the separator between the results that follow (do not use
|
||||
space, ",", ":" or non-ASCII).
|
||||
An in-memory table that performs random selection. Exam‐
|
||||
ple: "<b><a href="DATABASE_README.html#types">randmap</a>:{</b><i>result</i><b>_</b><i>1, ..., result</i><b>_</b><i>n</i><b>}</b>". Each table
|
||||
query returns a random choice from the specified results.
|
||||
The first and last characters of the "<a href="DATABASE_README.html#types">randmap</a>:" table
|
||||
name must be "<b>{</b>" and "<b>}</b>". Within these, individual maps
|
||||
are separated with comma or whitespace.
|
||||
|
||||
<b>regexp</b> (read-only)
|
||||
A lookup table based on regular expressions. The file
|
||||
A lookup table based on regular expressions. The file
|
||||
format is described in <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a>.
|
||||
|
||||
<b>sdbm</b> An indexed file type based on hashing. Available on sys-
|
||||
<b>sdbm</b> An indexed file type based on hashing. Available on sys‐
|
||||
tems with support for SDBM databases.
|
||||
|
||||
<b>socketmap</b> (read-only)
|
||||
Sendmail-style socketmap client. The table name is
|
||||
<b>inet</b>:<i>host</i>:<i>port</i>:<i>name</i> for a TCP/IP server, or <b>unix</b>:<i>path-</i>
|
||||
<i>name</i>:<i>name</i> for a UNIX-domain server. This is described in
|
||||
Sendmail-style socketmap client. The table name is
|
||||
<b>inet</b>:<i>host</i>:<i>port</i>:<i>name</i> for a TCP/IP server, or <b>unix</b>:<i>path‐</i>
|
||||
<i>name</i>:<i>name</i> for a UNIX-domain server. This is described in
|
||||
<a href="socketmap_table.5.html"><b>socketmap_table</b>(5)</a>.
|
||||
|
||||
<b>sqlite</b> (read-only)
|
||||
SQLite database. This is described in <a href="sqlite_table.5.html"><b>sqlite_table</b>(5)</a>.
|
||||
|
||||
<b>static</b> (read-only)
|
||||
A table that always returns its name as lookup result.
|
||||
For example, <b><a href="DATABASE_README.html#types">static</a>:foobar</b> always returns the string <b>foo-</b>
|
||||
A table that always returns its name as lookup result.
|
||||
For example, <b><a href="DATABASE_README.html#types">static</a>:foobar</b> always returns the string <b>foo</b>‐‐
|
||||
<b>bar</b> as lookup result.
|
||||
|
||||
<b>tcp</b> (read-only)
|
||||
TCP/IP client. The protocol is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
|
||||
|
||||
<b>texthash</b> (read-only)
|
||||
Produces similar results as <a href="DATABASE_README.html#types">hash</a>: files, except that you
|
||||
don't need to run the <a href="postmap.1.html"><b>postmap</b>(1)</a> command before you can
|
||||
use the file, and that it does not detect changes after
|
||||
Produces similar results as <a href="DATABASE_README.html#types">hash</a>: files, except that you
|
||||
don't need to run the <a href="postmap.1.html"><b>postmap</b>(1)</a> command before you can
|
||||
use the file, and that it does not detect changes after
|
||||
the file is read.
|
||||
|
||||
<b>unix</b> (read-only)
|
||||
A limited view of the UNIX authentication database. The
|
||||
A limited view of the UNIX authentication database. The
|
||||
following tables are implemented:
|
||||
|
||||
<b>unix:passwd.byname</b>
|
||||
The table is the UNIX password database. The key
|
||||
is a login name. The result is a password file
|
||||
The table is the UNIX password database. The key
|
||||
is a login name. The result is a password file
|
||||
entry in <b>passwd</b>(5) format.
|
||||
|
||||
<b>unix:group.byname</b>
|
||||
The table is the UNIX group database. The key is a
|
||||
group name. The result is a group file entry in
|
||||
group name. The result is a group file entry in
|
||||
<b>group</b>(5) format.
|
||||
|
||||
Other table types may exist depending on how Postfix was built.
|
||||
Other table types may exist depending on how Postfix was built.
|
||||
|
||||
<b>-M</b> Show <a href="master.5.html"><b>master.cf</b></a> file contents instead of <a href="postconf.5.html"><b>main.cf</b></a> file contents.
|
||||
<b>-M</b> Show <a href="master.5.html"><b>master.cf</b></a> file contents instead of <a href="postconf.5.html"><b>main.cf</b></a> file contents.
|
||||
Specify <b>-Mf</b> to fold long lines for human readability.
|
||||
|
||||
Specify zero or more arguments, each with a <i>service-name</i> or <i>ser-</i>
|
||||
<i>vice-name/service-type</i> pair, where <i>service-name</i> is the first
|
||||
field of a <a href="master.5.html">master.cf</a> entry and <i>service-type</i> is one of (<b>inet</b>,
|
||||
Specify zero or more arguments, each with a <i>service-name</i> or <i>ser‐</i>
|
||||
<i>vice-name/service-type</i> pair, where <i>service-name</i> is the first
|
||||
field of a <a href="master.5.html">master.cf</a> entry and <i>service-type</i> is one of (<b>inet</b>,
|
||||
<b>unix</b>, <b>fifo</b>, or <b>pass</b>).
|
||||
|
||||
If <i>service-name</i> or <i>service-name/service-type</i> is specified, only
|
||||
the matching <a href="master.5.html">master.cf</a> entries will be output. For example,
|
||||
"<b>postconf -Mf smtp</b>" will output all services named "smtp", and
|
||||
"<b>postconf -Mf smtp/inet</b>" will output only the smtp service that
|
||||
listens on the network. Trailing service type fields that are
|
||||
If <i>service-name</i> or <i>service-name/service-type</i> is specified, only
|
||||
the matching <a href="master.5.html">master.cf</a> entries will be output. For example,
|
||||
"<b>postconf -Mf smtp</b>" will output all services named "smtp", and
|
||||
"<b>postconf -Mf smtp/inet</b>" will output only the smtp service that
|
||||
listens on the network. Trailing service type fields that are
|
||||
omitted will be handled as "*" wildcard fields.
|
||||
|
||||
This feature is available with Postfix 2.9 and later. The syntax
|
||||
was changed from "<i>name.type</i>" to "<i>name/type</i>", and "*" wildcard
|
||||
was changed from "<i>name.type</i>" to "<i>name/type</i>", and "*" wildcard
|
||||
support was added with Postfix 2.11.
|
||||
|
||||
<b>-n</b> Show only configuration parameters that have explicit <i>name=value</i>
|
||||
settings in <a href="postconf.5.html"><b>main.cf</b></a>. Specify <b>-nf</b> to fold long lines for human
|
||||
settings in <a href="postconf.5.html"><b>main.cf</b></a>. Specify <b>-nf</b> to fold long lines for human
|
||||
readability (Postfix 2.9 and later).
|
||||
|
||||
<b>-o</b> <i>name=value</i>
|
||||
@ -354,81 +353,81 @@ POSTCONF(1) POSTCONF(1)
|
||||
|
||||
This feature is available with Postfix 2.11 and later.
|
||||
|
||||
<b>-P</b> Show <a href="master.5.html"><b>master.cf</b></a> service parameter settings (by default all ser-
|
||||
vices and all parameters). formatted as one "<i>ser-</i>
|
||||
<i>vice/type/parameter=value</i>" per line. Specify <b>-Pf</b> to fold long
|
||||
<b>-P</b> Show <a href="master.5.html"><b>master.cf</b></a> service parameter settings (by default all ser‐
|
||||
vices and all parameters). formatted as one "<i>ser‐</i>
|
||||
<i>vice/type/parameter=value</i>" per line. Specify <b>-Pf</b> to fold long
|
||||
lines.
|
||||
|
||||
Specify one or more "<i>service/type/parameter</i>" instances on the
|
||||
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line to limit the output to parameters of
|
||||
interest. Trailing parameter name or service type fields that
|
||||
Specify one or more "<i>service/type/parameter</i>" instances on the
|
||||
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line to limit the output to parameters of
|
||||
interest. Trailing parameter name or service type fields that
|
||||
are omitted will be handled as "*" wildcard fields.
|
||||
|
||||
This feature is available with Postfix 2.11 and later.
|
||||
|
||||
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
|
||||
Display the templates for text that appears at the beginning of
|
||||
delivery status notification (DSN) messages, without expanding
|
||||
Display the templates for text that appears at the beginning of
|
||||
delivery status notification (DSN) messages, without expanding
|
||||
$<b>name</b> expressions.
|
||||
|
||||
To override the built-in templates, specify a template file name
|
||||
at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line, or specify a file
|
||||
at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line, or specify a file
|
||||
name in <a href="postconf.5.html"><b>main.cf</b></a> with the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter.
|
||||
|
||||
To force selection of the built-in templates, specify an empty
|
||||
template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line (in shell
|
||||
To force selection of the built-in templates, specify an empty
|
||||
template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line (in shell
|
||||
language: "").
|
||||
|
||||
This feature is available with Postfix 2.3 and later.
|
||||
|
||||
<b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
|
||||
<b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
|
||||
options make the software increasingly verbose.
|
||||
|
||||
<b>-x</b> Expand <i>$name</i> in <a href="postconf.5.html"><b>main.cf</b></a> or <a href="master.5.html"><b>master.cf</b></a> parameter values. The
|
||||
<b>-x</b> Expand <i>$name</i> in <a href="postconf.5.html"><b>main.cf</b></a> or <a href="master.5.html"><b>master.cf</b></a> parameter values. The
|
||||
expansion is recursive.
|
||||
|
||||
This feature is available with Postfix 2.10 and later.
|
||||
|
||||
<b>-X</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and remove the parameters
|
||||
named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. Specify a list of param-
|
||||
<b>-X</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and remove the parameters
|
||||
named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. Specify a list of param‐
|
||||
eter names, not "<i>name=value</i>" pairs.
|
||||
|
||||
With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and remove one
|
||||
or more service entries as specified with "<i>service/type</i>" on the
|
||||
With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and remove one
|
||||
or more service entries as specified with "<i>service/type</i>" on the
|
||||
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
With <b>-P</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and remove one
|
||||
With <b>-P</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and remove one
|
||||
or more service parameter settings (-o parameter=value settings)
|
||||
as specied with "<i>service/type/parameter</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
|
||||
as specied with "<i>service/type/parameter</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> com‐
|
||||
mand line.
|
||||
|
||||
In all cases the file is copied to a temporary file then renamed
|
||||
into place. Specify quotes to protect special characters on the
|
||||
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera-
|
||||
There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera‐
|
||||
tion.
|
||||
|
||||
This feature is available with Postfix 2.10 and later. Support
|
||||
This feature is available with Postfix 2.10 and later. Support
|
||||
for -M and -P was added with Postfix 2.11.
|
||||
|
||||
<b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment out the parame-
|
||||
ters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line, so that those param-
|
||||
eters revert to their default values. Specify a list of parame-
|
||||
<b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment out the parame‐
|
||||
ters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line, so that those param‐
|
||||
eters revert to their default values. Specify a list of parame‐
|
||||
ter names, not "<i>name=value</i>" pairs.
|
||||
|
||||
With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and comment out
|
||||
one or more service entries as specified with "<i>service/type</i>" on
|
||||
With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and comment out
|
||||
one or more service entries as specified with "<i>service/type</i>" on
|
||||
the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
In all cases the file is copied to a temporary file then renamed
|
||||
into place. Specify quotes to protect special characters on the
|
||||
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
|
||||
|
||||
There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera-
|
||||
There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera‐
|
||||
tion.
|
||||
|
||||
This feature is available with Postfix 2.6 and later. Support
|
||||
This feature is available with Postfix 2.6 and later. Support
|
||||
for -M was added with Postfix 2.11.
|
||||
|
||||
<b>DIAGNOSTICS</b>
|
||||
@ -439,18 +438,18 @@ POSTCONF(1) POSTCONF(1)
|
||||
Directory with Postfix configuration files.
|
||||
|
||||
<b>CONFIGURATION PARAMETERS</b>
|
||||
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
|
||||
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro‐
|
||||
gram.
|
||||
|
||||
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#bounce_template_file">bounce_template_file</a> (empty)</b>
|
||||
Pathname of a configuration file with bounce message templates.
|
||||
Pathname of a configuration file with bounce message templates.
|
||||
|
||||
<b>FILES</b>
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>, Postfix configuration parameters
|
||||
|
@ -42,19 +42,40 @@ that starts with whitespace continues a logical line. </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> The expressions "$name", "${name}" or "$(name)" are
|
||||
recursively replaced by the value of the named parameter. </p>
|
||||
<li> <p> The expressions "$name" and "${name}" are recursively
|
||||
replaced with the value of the named parameter, except where noted.
|
||||
An undefined parameter value is replaced with the empty value. </p>
|
||||
|
||||
<li> <p> The expression "${name?value}" expands to "value" when
|
||||
"$name" is non-empty. This form is supported with Postfix version
|
||||
2.2 and later. </p>
|
||||
<li> <p> The expressions "${name?value}" and "${name?{value}}" are
|
||||
replaced with "value" when "$name" is non-empty. These forms are
|
||||
supported with Postfix versions ≥ 2.2 and ≥ 2.12, respectively.
|
||||
</p>
|
||||
|
||||
<li> <p> The expression "${name:value}" expands to "value" when
|
||||
"$name" is empty. This form is supported with Postfix version 2.2
|
||||
and later. </p>
|
||||
<li> <p> The expressions "${name:value}" and "${name?{value}}" are
|
||||
replaced with "value" when "$name" is empty. These forms are supported
|
||||
with Postfix versions ≥ 2.2 and ≥ 2.12, respectively. </p>
|
||||
|
||||
<li> <p> The expression "${name?{value1}:{value2}}" is replaced
|
||||
with "value1" when "$name" is non-empty, and with "value2" when
|
||||
"$name" is empty. The "{}" is required for "value1", optional for
|
||||
"value2". This form is supported with Postfix versions ≥ 2.12.
|
||||
</p>
|
||||
|
||||
<li> <p> Instead of a parameter name, the first item inside "${...}"
|
||||
may be a logical expression of the form: "{value3} == {value4}"
|
||||
(equality) or "{value3} != {value4}" (inequality). This form is
|
||||
supported with Postfix versions ≥ 2.12. </p>
|
||||
|
||||
<li> <p> Each "value" is subject to recursive named parameter and
|
||||
logical expression evaluation, except where noted. </p>
|
||||
|
||||
<li> <p> Whitespace before or after each "{value}" is ignored. </p>
|
||||
|
||||
<li> <p> Specify "$$" to produce a single "$" character. </p>
|
||||
|
||||
<li> <p> The legacy form "$(...)" is equivalent to the preferred
|
||||
form "${...}". </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<li> <p> When the same parameter is defined multiple times, only
|
||||
|
@ -14,11 +14,11 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server provides read-only or read-write table lookup
|
||||
service to Postfix processes. These services are implemented with dis-
|
||||
service to Postfix processes. These services are implemented with dis‐
|
||||
tinct service names: <b>proxymap</b> and <b>proxywrite</b>, respectively. The purpose
|
||||
of these services is:
|
||||
|
||||
<b>o</b> To overcome chroot restrictions. For example, a chrooted SMTP
|
||||
· To overcome chroot restrictions. For example, a chrooted SMTP
|
||||
server needs access to the system passwd file in order to reject
|
||||
mail for non-existent local addresses, but it is not practical
|
||||
to maintain a copy of the passwd file in the chroot jail. The
|
||||
@ -27,7 +27,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> =
|
||||
<a href="proxymap.8.html">proxy</a>:unix:passwd.byname $<a href="postconf.5.html#alias_maps">alias_maps</a>
|
||||
|
||||
<b>o</b> To consolidate the number of open lookup tables by sharing one
|
||||
· To consolidate the number of open lookup tables by sharing one
|
||||
open table among multiple processes. For example, making mysql
|
||||
connections from every Postfix daemon process results in "too
|
||||
many connections" errors. The solution:
|
||||
@ -38,7 +38,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
The total number of connections is limited by the number of
|
||||
proxymap server processes.
|
||||
|
||||
<b>o</b> To provide single-updater functionality for lookup tables that
|
||||
· To provide single-updater functionality for lookup tables that
|
||||
do not reliably support multiple writers (i.e. all file-based
|
||||
tables).
|
||||
|
||||
@ -47,7 +47,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
<b>open</b> <i>maptype:mapname flags</i>
|
||||
Open the table with type <i>maptype</i> and name <i>mapname</i>, as controlled
|
||||
by <i>flags</i>. The reply includes the <i>maptype</i> dependent flags (to
|
||||
distinguish a fixed string table from a regular expression ta-
|
||||
distinguish a fixed string table from a regular expression ta‐
|
||||
ble).
|
||||
|
||||
<b>lookup</b> <i>maptype:mapname flags key</i>
|
||||
@ -101,7 +101,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server opens only tables that are approved via the
|
||||
<b><a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a></b> or <b><a href="postconf.5.html#proxy_write_maps">proxy_write_maps</a></b> configuration parameters, does not
|
||||
talk to users, and can run at fixed low privilege, chrooted or not.
|
||||
However, running the proxymap server chrooted severely limits usabil-
|
||||
However, running the proxymap server chrooted severely limits usabil‐
|
||||
ity, because it can open only chrooted tables.
|
||||
|
||||
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server is not a trusted daemon process, and must not be
|
||||
@ -113,7 +113,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
the table directly. This allows the same <a href="postconf.5.html">main.cf</a> setting to be used by
|
||||
sensitive and non-sensitive processes.
|
||||
|
||||
Postfix-writable data files should be stored under a dedicated direc-
|
||||
Postfix-writable data files should be stored under a dedicated direc‐
|
||||
tory that is writable only by the Postfix mail system, such as the
|
||||
Postfix-owned <b><a href="postconf.5.html#data_directory">data_directory</a></b>.
|
||||
|
||||
@ -131,7 +131,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
|
||||
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> read-write service does not explicitly close lookup
|
||||
tables (even if it did, this could not be relied on, because the
|
||||
process may be terminated between table updates). The read-write ser-
|
||||
process may be terminated between table updates). The read-write ser‐
|
||||
vice should therefore not be used with tables that leave persistent
|
||||
storage in an inconsistent state between updates (for example, CDB).
|
||||
Tables that support "sync on update" should be safe (for example,
|
||||
@ -146,7 +146,7 @@ PROXYMAP(8) PROXYMAP(8)
|
||||
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#data_directory">data_directory</a> (see 'postconf -d' output)</b>
|
||||
|
@ -16,13 +16,13 @@ QMQP-SINK(1) QMQP-SINK(1)
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
<b>qmqp-sink</b> listens on the named host (or address) and port. It receives
|
||||
messages from the network and throws them away. The purpose is to mea-
|
||||
messages from the network and throws them away. The purpose is to mea‐
|
||||
sure QMQP client performance, not protocol compliance. Connections can
|
||||
be accepted on IPv4 or IPv6 endpoints, or on UNIX-domain sockets. IPv4
|
||||
and IPv6 are the default. This program is the complement of the <a href="qmqp-source.1.html"><b>qmqp-</b></a>
|
||||
<a href="qmqp-source.1.html"><b>source</b>(1)</a> program.
|
||||
|
||||
Note: this is an unsupported test program. No attempt is made to main-
|
||||
Note: this is an unsupported test program. No attempt is made to main‐
|
||||
tain compatibility between successive versions.
|
||||
|
||||
Arguments:
|
||||
@ -36,7 +36,7 @@ QMQP-SINK(1) QMQP-SINK(1)
|
||||
<b>-c</b> Display a running counter that is updated whenever a delivery is
|
||||
completed.
|
||||
|
||||
<b>-v</b> Increase verbosity. Specify <b>-v -v</b> to see some of the QMQP con-
|
||||
<b>-v</b> Increase verbosity. Specify <b>-v -v</b> to see some of the QMQP con‐
|
||||
versation.
|
||||
|
||||
<b>-x</b> <i>time</i>
|
||||
|
@ -19,7 +19,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
SMTP messages from the network and throws them away. The purpose is to
|
||||
measure client performance, not protocol compliance.
|
||||
|
||||
<b>smtp-sink</b> may also be configured to capture each mail delivery transac-
|
||||
<b>smtp-sink</b> may also be configured to capture each mail delivery transac‐
|
||||
tion to file. Since disk latencies are large compared to network
|
||||
delays, this mode of operation can reduce the maximal performance by
|
||||
several orders of magnitude.
|
||||
@ -28,7 +28,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
domain sockets. IPv4 and IPv6 are the default. This program is the
|
||||
complement of the <a href="smtp-source.1.html"><b>smtp-source</b>(1)</a> program.
|
||||
|
||||
Note: this is an unsupported test program. No attempt is made to main-
|
||||
Note: this is an unsupported test program. No attempt is made to main‐
|
||||
tain compatibility between successive versions.
|
||||
|
||||
Arguments:
|
||||
@ -44,7 +44,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
<b>-a</b> Do not announce SASL authentication support.
|
||||
|
||||
<b>-A</b> <i>delay</i>
|
||||
Wait <i>delay</i> seconds after responding to DATA, then abort prema-
|
||||
Wait <i>delay</i> seconds after responding to DATA, then abort prema‐
|
||||
turely with a 550 reply status. Do not read further input from
|
||||
the client; this is an attempt to block the client before it
|
||||
sends ".". Specify a zero delay value to abort immediately.
|
||||
@ -57,7 +57,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
Use <i>hard-bounce-reply</i> for hard reject responses. The default
|
||||
reply is "500 5.3.0 Error: command failed".
|
||||
|
||||
<b>-c</b> Display running counters that are updated whenever an SMTP ses-
|
||||
<b>-c</b> Display running counters that are updated whenever an SMTP ses‐
|
||||
sion ends, a QUIT command is executed, or when "." is received.
|
||||
|
||||
<b>-C</b> Disable XCLIENT support.
|
||||
@ -67,7 +67,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
is created by expanding the <i>dump-template</i> via strftime(3) and
|
||||
appending a pseudo-random hexadecimal number (example:
|
||||
"%Y%m%d%H/%M." expands into "2006081203/05.809a62e3"). If the
|
||||
template contains "/" characters, missing directories are cre-
|
||||
template contains "/" characters, missing directories are cre‐
|
||||
ated automatically. The message dump format is described below.
|
||||
|
||||
Note: this option keeps one capture file open for every mail
|
||||
@ -106,7 +106,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
|
||||
<b>-m</b> <i>count</i> (default: 256)
|
||||
An upper bound on the maximal number of simultaneous connections
|
||||
that <b>smtp-sink</b> will handle. This prevents the process from run-
|
||||
that <b>smtp-sink</b> will handle. This prevents the process from run‐
|
||||
ning out of file descriptors. Excess connections will stay
|
||||
queued in the TCP/IP stack.
|
||||
|
||||
@ -122,7 +122,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
CISCO PIX system. Implies <b>-e</b>.
|
||||
|
||||
<b>-q</b> <i>command,command,...</i>
|
||||
Disconnect (without replying) after receiving one of the speci-
|
||||
Disconnect (without replying) after receiving one of the speci‐
|
||||
fied commands.
|
||||
|
||||
Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT,
|
||||
@ -131,7 +131,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
from the shell. Command names are case-insensitive.
|
||||
|
||||
<b>-Q</b> <i>command,command,...</i>
|
||||
Send a 421 reply and disconnect after receiving one of the spec-
|
||||
Send a 421 reply and disconnect after receiving one of the spec‐
|
||||
ified commands.
|
||||
|
||||
Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT,
|
||||
@ -165,7 +165,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
An optional string that is prepended to each message that is
|
||||
written to a dump file (see the dump file format description
|
||||
below). The following C escape sequences are supported: \a
|
||||
(bell), \b (backslace), \f (formfeed), \n (newline), \r (car-
|
||||
(bell), \b (backslace), \f (formfeed), \n (newline), \r (car‐
|
||||
riage return), \t (horizontal tab), \v (vertical tab), \<i>ddd</i> (up
|
||||
to three octal digits) and \\ (the backslash character).
|
||||
|
||||
@ -178,7 +178,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
window scaling implementations, specify a value > 0 and < 65536.
|
||||
|
||||
<b>-u</b> <i>username</i>
|
||||
Switch to the specified user privileges after opening the net-
|
||||
Switch to the specified user privileges after opening the net‐
|
||||
work socket and optionally changing the process root directory.
|
||||
This option is required when the process runs with super-user
|
||||
privileges. See also the <b>-R</b> option.
|
||||
@ -212,13 +212,13 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
Each dumped message contains a sequence of text lines, terminated with
|
||||
the newline character. The sequence of information is as follows:
|
||||
|
||||
<b>o</b> The optional string specified with the <b>-S</b> option.
|
||||
· The optional string specified with the <b>-S</b> option.
|
||||
|
||||
<b>o</b> The <b>smtp-sink</b> generated headers as documented below.
|
||||
· The <b>smtp-sink</b> generated headers as documented below.
|
||||
|
||||
<b>o</b> The message header and body as received from the SMTP client.
|
||||
· The message header and body as received from the SMTP client.
|
||||
|
||||
<b>o</b> An empty line.
|
||||
· An empty line.
|
||||
|
||||
The format of the <b>smtp-sink</b> generated headers is as follows:
|
||||
|
||||
@ -233,11 +233,11 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
<b>X-Helo-Args:</b> <i>text</i>
|
||||
The arguments of the last HELO or EHLO command before this mail
|
||||
delivery transaction. This record is present only if the client
|
||||
sent a recognizable HELO or EHLO command before the DATA com-
|
||||
sent a recognizable HELO or EHLO command before the DATA com‐
|
||||
mand.
|
||||
|
||||
<b>X-Mail-Args:</b> <i>text</i>
|
||||
The arguments of the MAIL command that started this mail deliv-
|
||||
The arguments of the MAIL command that started this mail deliv‐
|
||||
ery transaction. This record is present exactly once.
|
||||
|
||||
<b>X-Rcpt-Args:</b> <i>text</i>
|
||||
@ -246,8 +246,8 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
are in the order as sent by the client.
|
||||
|
||||
<b>Received:</b> <i>text</i>
|
||||
A message header for compatibility with mail processing soft-
|
||||
ware. This three-line header marks the end of the headers pro-
|
||||
A message header for compatibility with mail processing soft‐
|
||||
ware. This three-line header marks the end of the headers pro‐
|
||||
vided by <b>smtp-sink</b>, and is formatted as follows:
|
||||
|
||||
<b>from</b> <i>helo</i> <b>([</b><i>addr</i><b>])</b>
|
||||
@ -257,7 +257,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
||||
|
||||
<b>by</b> <i>host</i> <b>(smtp-sink) with</b> <i>proto</i> <b>id</b> <i>random</i><b>;</b>
|
||||
The hostname specified with the <b>-h</b> option, the client
|
||||
protocol (see <b>X-Client-Proto</b> above), and the pseudo-ran-
|
||||
protocol (see <b>X-Client-Proto</b> above), and the pseudo-ran‐
|
||||
dom portion of the per-message capture file name.
|
||||
|
||||
<i>time-stamp</i>
|
||||
|
@ -274,25 +274,26 @@ The file format is described in \fBpcre_table\fR(5).
|
||||
PostgreSQL database client. This is described in
|
||||
\fBpgsql_table\fR(5).
|
||||
.IP "\fBpipemap\fR (read-only)"
|
||||
A pipeline of lookup tables. Example:
|
||||
"\fBpipemap:\fI!type_1:name_1! ... !type_n:name_n\fR".
|
||||
A lookup table that constructs a pipeline of tables. Example:
|
||||
"\fBpipemap:{\fItype_1:name_1, ..., type_n:name_n\fB}\fR".
|
||||
Each "pipemap:" query is given to the first table. Each
|
||||
lookup result becomes the query for the next table in the
|
||||
pipeline, and the last table produces the final result.
|
||||
When any table lookup produces no result, the pipeline
|
||||
produces no result. The first ASCII character after "pipemap:"
|
||||
will be used as the separator between the lookup tables
|
||||
that follow (do not use space, ",", ":" or non-ASCII).
|
||||
produces no result. The first and last characters of the
|
||||
"pipemap:" table name must be "\fB{\fR" and "\fB}\fR".
|
||||
Within these, individual maps are separated with comma or
|
||||
whitespace.
|
||||
.IP "\fBproxy\fR"
|
||||
Postfix \fBproxymap\fR(8) client for shared access to Postfix
|
||||
databases. The table name syntax is \fItype\fB:\fIname\fR.
|
||||
.IP "\fBrandmap\fR (read-only)"
|
||||
An in-memory table that performs random selection. Example:
|
||||
"\fBrandmap:\fI!result_1! ... !result_n\fR". Each table query
|
||||
"\fBrandmap:{\fIresult_1, ..., result_n\fB}\fR". Each table query
|
||||
returns a random choice from the specified results. The first
|
||||
ASCII character after "randmap:" will be used as the separator
|
||||
between the results that follow (do not use space, ",", ":"
|
||||
or non-ASCII).
|
||||
and last characters of the "randmap:" table name must be
|
||||
"\fB{\fR" and "\fB}\fR". Within these, individual maps are
|
||||
separated with comma or whitespace.
|
||||
.IP "\fBregexp\fR (read-only)"
|
||||
A lookup table based on regular expressions. The file format
|
||||
is described in \fBregexp_table\fR(5).
|
||||
|
@ -32,18 +32,36 @@ with whitespace continues a logical line.
|
||||
A parameter value may refer to other parameters.
|
||||
.RS
|
||||
.IP \(bu
|
||||
The expressions "$name", "${name}" or "$(name)" are
|
||||
recursively replaced by the value of the named parameter.
|
||||
The expressions "$name" and "${name}" are recursively replaced with
|
||||
the value of the named parameter. An undefined parameter value is
|
||||
replaced with the empty value.
|
||||
.IP \(bu
|
||||
The expression "${name?value}" expands to "value" when
|
||||
"$name" is non-empty. This form is supported with Postfix
|
||||
version 2.2 and later.
|
||||
The expressions "${name?value}" and "${name?{value}}" are replaced
|
||||
with "value" when "$name" is non-empty. These forms are supported
|
||||
with Postfix versions >= 2.2 and >= 2.12, respectively.
|
||||
.IP \(bu
|
||||
The expression "${name:value}" expands to "value" when
|
||||
"$name" is empty. This form is supported with Postfix
|
||||
version 2.2 and later.
|
||||
The expressions "${name:value}" and "${name:{value}}" are replaced
|
||||
with "value" when "$name" is empty. These forms are supported with
|
||||
Postfix versions >= 2.2 and >= 2.12, respectively.
|
||||
.IP \(bu
|
||||
The expression "${name?{value1}:{value2}}" is replaced with "value1"
|
||||
when "$name" is non-empty, and with "value2" when "$name" is empty.
|
||||
The "{}" is required for "value1", optional for "value2". This form
|
||||
is supported with Postfix versions >= 2.12.
|
||||
.IP \(bu
|
||||
Instead of a parameter name, the first item inside "${...}" may be
|
||||
a logical expression of the form: "{value3} == {value4}" (equality)
|
||||
or "{value3} != {value4}" (inequality). This form is supported
|
||||
with Postfix versions >= 2.12.
|
||||
.IP \(bu
|
||||
Each "value" is subject to recursive named parameter and logical
|
||||
expression evaluation, except where noted.
|
||||
.IP \(bu
|
||||
Whitespace before or after each "{value}" is ignored.
|
||||
.IP \(bu
|
||||
Specify "$$" to produce a single "$" character.
|
||||
.IP \(bu
|
||||
The legacy form "$(...)" is equivalent to the preferred form "${...}".
|
||||
.RE
|
||||
.IP \(bu
|
||||
When the same parameter is defined multiple times, only the last
|
||||
|
@ -365,14 +365,14 @@ file. </dd>
|
||||
<dt> <b>pipemap</b> (read-only) </dt>
|
||||
|
||||
<dd> A pipeline of lookup tables. Example:
|
||||
"<b>pipemap:</b><i>!type<sub>1</sub>:name<sub>1</sub>! ...
|
||||
!type<sub>n</sub>:name<sub>n</sub></i>". Each "pipemap:" query is
|
||||
"pipemap:{<i>type<sub>1</sub>:name<sub>1</sub>, ...,
|
||||
type<sub>n</sub>:name<sub>n</sub></i>}". Each "pipemap:" query is
|
||||
given to the first table. Each lookup result becomes the query for
|
||||
the next table in the pipeline, and the last table produces the
|
||||
final result. When any table lookup produces no result, the pipeline
|
||||
produces no result. The first ASCII character after "pipemap:"
|
||||
will be used as the separator between the lookup tables that follow
|
||||
(do not use space, ",", ":" or non-ASCII). </dd>
|
||||
produces no result. The first and last characters of the "pipemap:"
|
||||
table name must be "{" and "}". Within these, individual maps are
|
||||
separated with comma or whitespace. </dd>
|
||||
|
||||
<dt> <b>pgsql</b> (read-only) </dt>
|
||||
|
||||
@ -388,11 +388,11 @@ databases. The lookup table name syntax is "proxy:type:table".
|
||||
<dt> <b>randmap</b> (read-only) </dt>
|
||||
|
||||
<dd> An in-memory table that performs random selection. Example:
|
||||
"<b>randmap:</b><i>!result<sub>1</sub>! ... !result<sub>n</sub></i>".
|
||||
"randmap:{<i>result<sub>1</sub>. ..., result<sub>n</sub></i>}".
|
||||
Each table query returns a random choice from the specified results.
|
||||
The first ASCII character after "randmap:" will be used as the
|
||||
separator between the results that follow (do not use space, ",",
|
||||
":" or non-ASCII). </dd>
|
||||
The first and last characters of the "randmap:" table name must be
|
||||
"{" and "}". Within these, individual maps are separated with comma
|
||||
or whitespace. </dd>
|
||||
|
||||
<dt> <b>regexp</b> (read-only) </dt>
|
||||
|
||||
|
@ -42,19 +42,40 @@ that starts with whitespace continues a logical line. </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> The expressions "$name", "${name}" or "$(name)" are
|
||||
recursively replaced by the value of the named parameter. </p>
|
||||
<li> <p> The expressions "$name" and "${name}" are recursively
|
||||
replaced with the value of the named parameter, except where noted.
|
||||
An undefined parameter value is replaced with the empty value. </p>
|
||||
|
||||
<li> <p> The expression "${name?value}" expands to "value" when
|
||||
"$name" is non-empty. This form is supported with Postfix version
|
||||
2.2 and later. </p>
|
||||
<li> <p> The expressions "${name?value}" and "${name?{value}}" are
|
||||
replaced with "value" when "$name" is non-empty. These forms are
|
||||
supported with Postfix versions ≥ 2.2 and ≥ 2.12, respectively.
|
||||
</p>
|
||||
|
||||
<li> <p> The expression "${name:value}" expands to "value" when
|
||||
"$name" is empty. This form is supported with Postfix version 2.2
|
||||
and later. </p>
|
||||
<li> <p> The expressions "${name:value}" and "${name?{value}}" are
|
||||
replaced with "value" when "$name" is empty. These forms are supported
|
||||
with Postfix versions ≥ 2.2 and ≥ 2.12, respectively. </p>
|
||||
|
||||
<li> <p> The expression "${name?{value1}:{value2}}" is replaced
|
||||
with "value1" when "$name" is non-empty, and with "value2" when
|
||||
"$name" is empty. The "{}" is required for "value1", optional for
|
||||
"value2". This form is supported with Postfix versions ≥ 2.12.
|
||||
</p>
|
||||
|
||||
<li> <p> Instead of a parameter name, the first item inside "${...}"
|
||||
may be a logical expression of the form: "{value3} == {value4}"
|
||||
(equality) or "{value3} != {value4}" (inequality). This form is
|
||||
supported with Postfix versions ≥ 2.12. </p>
|
||||
|
||||
<li> <p> Each "value" is subject to recursive named parameter and
|
||||
logical expression evaluation, except where noted. </p>
|
||||
|
||||
<li> <p> Whitespace before or after each "{value}" is ignored. </p>
|
||||
|
||||
<li> <p> Specify "$$" to produce a single "$" character. </p>
|
||||
|
||||
<li> <p> The legacy form "$(...)" is equivalent to the preferred
|
||||
form "${...}". </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<li> <p> When the same parameter is defined multiple times, only
|
||||
|
@ -32,18 +32,36 @@ with whitespace continues a logical line.
|
||||
A parameter value may refer to other parameters.
|
||||
.RS
|
||||
.IP \(bu
|
||||
The expressions "$name", "${name}" or "$(name)" are
|
||||
recursively replaced by the value of the named parameter.
|
||||
The expressions "$name" and "${name}" are recursively replaced with
|
||||
the value of the named parameter. An undefined parameter value is
|
||||
replaced with the empty value.
|
||||
.IP \(bu
|
||||
The expression "${name?value}" expands to "value" when
|
||||
"$name" is non-empty. This form is supported with Postfix
|
||||
version 2.2 and later.
|
||||
The expressions "${name?value}" and "${name?{value}}" are replaced
|
||||
with "value" when "$name" is non-empty. These forms are supported
|
||||
with Postfix versions >= 2.2 and >= 2.12, respectively.
|
||||
.IP \(bu
|
||||
The expression "${name:value}" expands to "value" when
|
||||
"$name" is empty. This form is supported with Postfix
|
||||
version 2.2 and later.
|
||||
The expressions "${name:value}" and "${name:{value}}" are replaced
|
||||
with "value" when "$name" is empty. These forms are supported with
|
||||
Postfix versions >= 2.2 and >= 2.12, respectively.
|
||||
.IP \(bu
|
||||
The expression "${name?{value1}:{value2}}" is replaced with "value1"
|
||||
when "$name" is non-empty, and with "value2" when "$name" is empty.
|
||||
The "{}" is required for "value1", optional for "value2". This form
|
||||
is supported with Postfix versions >= 2.12.
|
||||
.IP \(bu
|
||||
Instead of a parameter name, the first item inside "${...}" may be
|
||||
a logical expression of the form: "{value3} == {value4}" (equality)
|
||||
or "{value3} != {value4}" (inequality). This form is supported
|
||||
with Postfix versions >= 2.12.
|
||||
.IP \(bu
|
||||
Each "value" is subject to recursive named parameter and logical
|
||||
expression evaluation, except where noted.
|
||||
.IP \(bu
|
||||
Whitespace before or after each "{value}" is ignored.
|
||||
.IP \(bu
|
||||
Specify "$$" to produce a single "$" character.
|
||||
.IP \(bu
|
||||
The legacy form "$(...)" is equivalent to the preferred form "${...}".
|
||||
.RE
|
||||
.IP \(bu
|
||||
When the same parameter is defined multiple times, only the last
|
||||
|
@ -50,7 +50,7 @@ typedef struct BOUNCE_TEMPLATE {
|
||||
#define bounce_template_encoding(t) ((t)->mime_encoding)
|
||||
#define bounce_template_charset(t) ((t)->mime_charset)
|
||||
|
||||
typedef int (*BOUNCE_XP_PRN_FN) (VSTREAM *, const char *, ...);
|
||||
typedef int PRINTFLIKE(2, 3) (*BOUNCE_XP_PRN_FN) (VSTREAM *, const char *,...);
|
||||
typedef int (*BOUNCE_XP_PUT_FN) (VSTREAM *, const char *);
|
||||
|
||||
extern BOUNCE_TEMPLATE *bounce_template_create(const BOUNCE_TEMPLATE *);
|
||||
|
@ -580,8 +580,11 @@ static void cleanup_header_callback(void *context, int header_class,
|
||||
if (hdr_opts->type == HDR_RESENT_MESSAGE_ID)
|
||||
msg_info("%s: resent-message-id=%s", state->queue_id, hdrval);
|
||||
if (hdr_opts->type == HDR_RECEIVED)
|
||||
if (++state->hop_count >= var_hopcount_limit)
|
||||
if (++state->hop_count >= var_hopcount_limit) {
|
||||
msg_warn("%s: message rejected: hopcount exceeded",
|
||||
state->queue_id);
|
||||
state->errs |= CLEANUP_STAT_HOPS;
|
||||
}
|
||||
if (CLEANUP_OUT_OK(state)) {
|
||||
if (hdr_opts->flags & HDR_OPT_RR)
|
||||
state->resent = "Resent-";
|
||||
|
@ -227,7 +227,7 @@ int main(int argc, char **argv)
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
continue;
|
||||
}
|
||||
target = mystrtok(&bufp, " \t");
|
||||
target = mystrtokq(&bufp, " \t");
|
||||
junk = mystrtok(&bufp, " \t");
|
||||
if (strcmp(cmd, "file") == 0 && target && !junk) {
|
||||
data_redirect_file(result, target);
|
||||
|
@ -133,7 +133,7 @@ static int dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
|
||||
{
|
||||
VSTREAM *fp;
|
||||
int count;
|
||||
int data_len = strlen(value);
|
||||
size_t data_len = strlen(value);
|
||||
|
||||
/*
|
||||
* Return a permanent error if we can't store this data. This results in
|
||||
@ -153,7 +153,8 @@ static int dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
|
||||
if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
|
||||
break;
|
||||
} else if (memcache_printf(fp, "set %s %d %d %ld",
|
||||
STR(dict_mc->key_buf), dict_mc->mc_flags, ttl, data_len) < 0
|
||||
STR(dict_mc->key_buf), dict_mc->mc_flags,
|
||||
ttl, (long) data_len) < 0
|
||||
|| memcache_fwrite(fp, value, strlen(value)) < 0
|
||||
|| memcache_get(fp, dict_mc->clnt_buf,
|
||||
dict_mc->max_line) < 0) {
|
||||
|
@ -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 "20140907"
|
||||
#define MAIL_RELEASE_DATE "20140921"
|
||||
#define MAIL_VERSION_NUMBER "2.12"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -115,6 +115,7 @@ MAPS *maps_create(const char *title, const char *map_names, int dict_flags)
|
||||
char *temp;
|
||||
char *bufp;
|
||||
static char sep[] = " \t,\r\n";
|
||||
static char parens[] = "{}";
|
||||
MAPS *maps;
|
||||
char *map_type_name;
|
||||
VSTRING *map_type_name_flags;
|
||||
@ -138,7 +139,7 @@ MAPS *maps_create(const char *title, const char *map_names, int dict_flags)
|
||||
|
||||
#define OPEN_FLAGS O_RDONLY
|
||||
|
||||
while ((map_type_name = mystrtok(&bufp, sep)) != 0) {
|
||||
while ((map_type_name = mystrtokq(&bufp, sep, parens)) != 0) {
|
||||
vstring_sprintf(map_type_name_flags, "%s(%o,%s)",
|
||||
map_type_name, OPEN_FLAGS,
|
||||
dict_flags_str(dict_flags));
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
extern int memcache_get(VSTREAM *, VSTRING *, ssize_t);
|
||||
extern int memcache_vprintf(VSTREAM *, const char *, va_list);
|
||||
extern int memcache_printf(VSTREAM *, const char *fmt,...);
|
||||
extern int PRINTFLIKE(2, 3) memcache_printf(VSTREAM *, const char *fmt,...);
|
||||
extern int memcache_fread(VSTREAM *, VSTRING *, ssize_t);
|
||||
extern int memcache_fwrite(VSTREAM *, const char *, ssize_t);
|
||||
|
||||
|
@ -120,7 +120,7 @@ SERVER_ACL *server_acl_parse(const char *extern_acl, const char *origin)
|
||||
* chroot jail, while access lists are evaluated after entering the
|
||||
* chroot jail.
|
||||
*/
|
||||
while ((acl = mystrtok(&bp, SERVER_ACL_SEPARATORS)) != 0) {
|
||||
while ((acl = mystrtokq(&bp, SERVER_ACL_SEPARATORS, "{}")) != 0) {
|
||||
if (strchr(acl, ':') != 0) {
|
||||
if (strchr(origin, ':') != 0) {
|
||||
msg_warn("table %s: lookup result \"%s\" is not allowed"
|
||||
|
@ -49,7 +49,7 @@ tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
|
||||
test22 test23 test24 test25 test26 test27 test28 test29 test30 test4b \
|
||||
test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \
|
||||
test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
|
||||
test52 test53 test54 test55 test56
|
||||
test52 test53 test54 test55 test56 test57 test58
|
||||
|
||||
root_tests:
|
||||
|
||||
@ -72,6 +72,7 @@ test1: $(PROG) test1.ref
|
||||
touch main.cf master.cf
|
||||
echo smtpd_restriction_classes = foo bar >> main.cf
|
||||
echo foo = yes >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test1.tmp 2>&1
|
||||
diff test1.ref test1.tmp
|
||||
rm -f main.cf master.cf test1.tmp
|
||||
@ -83,6 +84,7 @@ test2: $(PROG) test2.ref
|
||||
touch main.cf master.cf
|
||||
echo restriction_classes = foo bar >> main.cf
|
||||
echo foo = yes >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test2.tmp 2>&1
|
||||
diff test2.ref test2.tmp
|
||||
rm -f main.cf master.cf test2.tmp
|
||||
@ -95,6 +97,7 @@ test3: $(PROG) test3.ref
|
||||
echo foo = yes >> main.cf
|
||||
echo 'bar = $$foo' >> main.cf
|
||||
echo 'always_bcc = $$bar' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test3.tmp 2>&1
|
||||
diff test3.ref test3.tmp
|
||||
rm -f main.cf master.cf test3.tmp
|
||||
@ -108,6 +111,7 @@ test4: $(PROG) test4.ref
|
||||
echo 'bar = $$foo' >> main.cf
|
||||
echo smtpd unix - n n - 0 smtpd >> master.cf
|
||||
echo ' -o always_bcc=$$bar' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test4.tmp 2>&1
|
||||
diff test4.ref test4.tmp
|
||||
rm -f main.cf master.cf test4.tmp
|
||||
@ -123,6 +127,7 @@ test4b: $(PROG) test4b.ref
|
||||
echo smtpd1 unix - n n - 0 smtpd >> master.cf
|
||||
echo ' -o foo=xxx -o bar=yyy -o baz=zzz' >> master.cf
|
||||
echo '#smtpd2 unix - n n - 0 smtpd' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test4b.tmp 2>&1
|
||||
diff test4b.ref test4b.tmp
|
||||
rm -f main.cf master.cf test4b.tmp
|
||||
@ -135,6 +140,7 @@ test5: $(PROG) test5.ref
|
||||
touch main.cf master.cf
|
||||
echo smtpd unix - n n - 0 smtpd >> master.cf
|
||||
echo ' -o bar=yes -o always_bcc=$$bar -o' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test5.tmp 2>&1
|
||||
diff test5.ref test5.tmp
|
||||
rm -f main.cf master.cf test5.tmp
|
||||
@ -145,6 +151,7 @@ test6: $(PROG) test6.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo whatevershebrings unix - n n - 0 pipe >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . 2>&1 | grep whatevershebrings >test6.tmp
|
||||
diff test6.ref test6.tmp
|
||||
rm -f main.cf master.cf test6.tmp
|
||||
@ -155,6 +162,7 @@ test7: $(PROG) test7.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo whatevershebrings unix - n n - 0 spawn >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . 2>&1 | grep whatevershebrings >test7.tmp
|
||||
diff test7.ref test7.tmp
|
||||
rm -f main.cf master.cf test7.tmp
|
||||
@ -164,6 +172,7 @@ test8: $(PROG) test8.ref
|
||||
touch main.cf master.cf
|
||||
echo whatevershebrings inet - n n - 0 spawn >> master.cf
|
||||
echo whatevershebrings_time_limit=1 >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . 2>&1 | grep whatevershebrings >test8.tmp
|
||||
diff test8.ref test8.tmp
|
||||
rm -f main.cf master.cf test8.tmp
|
||||
@ -173,6 +182,7 @@ test9: $(PROG) test9.ref
|
||||
touch main.cf master.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo bar unix - n n - 0 spawn >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -M '*'/inet >test9.tmp 2>&1
|
||||
diff test9.ref test9.tmp
|
||||
rm -f main.cf master.cf test9.tmp
|
||||
@ -182,6 +192,7 @@ test10: $(PROG) test10.ref
|
||||
touch main.cf master.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo bar unix - n n - 0 spawn >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -M bar/inet foo/unix >test10.tmp 2>&1
|
||||
diff test10.ref test10.tmp
|
||||
rm -f main.cf master.cf test10.tmp
|
||||
@ -191,6 +202,7 @@ test11: $(PROG) test11.ref
|
||||
touch main.cf master.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo bar unix - n n - 0 spawn >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -M >test11.tmp 2>&1
|
||||
diff test11.ref test11.tmp
|
||||
rm -f main.cf master.cf test11.tmp
|
||||
@ -205,6 +217,7 @@ test12: $(PROG) test12.ref
|
||||
echo ' -o always_bcc=$$bar -o' >> master.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo ' -o always_bcc=$$bar -o' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -M >test12.tmp 2>&1
|
||||
diff test12.ref test12.tmp
|
||||
rm -f main.cf master.cf test12.tmp
|
||||
@ -218,6 +231,7 @@ test13: $(PROG) test13.ref
|
||||
echo baz=xx >> main.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo ' -o smtpd_restriction_classes=bar' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test13.tmp 2>&1
|
||||
diff test13.ref test13.tmp
|
||||
rm -f main.cf master.cf test13.tmp
|
||||
@ -230,6 +244,7 @@ test14: $(PROG) test14.ref
|
||||
echo smtpd_restriction_classes=bar >> main.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo ' -o bar=yes -o baz=xx' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test14.tmp 2>&1
|
||||
diff test14.ref test14.tmp
|
||||
rm -f main.cf master.cf test14.tmp
|
||||
@ -243,6 +258,7 @@ test15: $(PROG) test15.ref
|
||||
echo baz=yy >> main.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo ' -o bar=yes -o always_bcc=$$bar$$baz' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test15.tmp 2>&1
|
||||
diff test15.ref test15.tmp
|
||||
rm -f main.cf master.cf test15.tmp
|
||||
@ -251,14 +267,14 @@ test15: $(PROG) test15.ref
|
||||
|
||||
test16: $(PROG) test16.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test16.tmp 2>&1
|
||||
diff test16.ref test16.tmp
|
||||
rm -f main.cf master.cf test16.tmp
|
||||
|
||||
test17: $(PROG) test17.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
-./$(PROG) -Mc . >test17.tmp 2>&1; exit 0
|
||||
diff test17.ref test17.tmp
|
||||
rm -f main.cf master.cf test17.tmp
|
||||
@ -270,6 +286,7 @@ test18: $(PROG) test18.ref
|
||||
touch main.cf master.cf
|
||||
echo virtual_maps=xxx >> main.cf
|
||||
echo smtpd_client_connection_limit_exceptions=yyy >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test18.tmp 2>&1
|
||||
diff test18.ref test18.tmp
|
||||
rm -f main.cf master.cf test18.tmp
|
||||
@ -281,6 +298,7 @@ test19: $(PROG) test19.ref
|
||||
touch main.cf master.cf
|
||||
echo forward_path='$$'aaaa >> main.cf
|
||||
echo default_rbl_reply='$$'bbbb >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test19.tmp 2>&1
|
||||
diff test19.ref test19.tmp
|
||||
rm -f main.cf master.cf test19.tmp
|
||||
@ -292,6 +310,7 @@ test20: $(PROG) test20.ref
|
||||
touch main.cf master.cf
|
||||
echo foo inet - n n - 0 spawn >> master.cf
|
||||
echo ' -o always_bcc=$$bar$$baz' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc . >test20.tmp 2>&1
|
||||
diff test20.ref test20.tmp
|
||||
rm -f main.cf master.cf test20.tmp
|
||||
@ -303,6 +322,7 @@ test21: $(PROG) test21.ref
|
||||
touch main.cf master.cf
|
||||
echo forward_path = xxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxx \
|
||||
xxxxxxxxxxxxx xxxxxxxxxxxxxx >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nfc . >test21.tmp 2>&1
|
||||
diff test21.ref test21.tmp
|
||||
rm -f main.cf master.cf test21.tmp
|
||||
@ -313,6 +333,7 @@ test22: $(PROG) test22.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . 2>&1 | grep whatevershebrings >test22.tmp
|
||||
diff test22.ref test22.tmp
|
||||
rm -f main.cf master.cf test22.tmp
|
||||
@ -326,6 +347,7 @@ test23: $(PROG) test23.ref
|
||||
echo name = value >> main.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
echo ' -o always_bcc=$$name' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -nC builtin >test23.tmp 2>&1
|
||||
diff test23.ref test23.tmp
|
||||
rm -f main.cf master.cf test23.tmp
|
||||
@ -337,6 +359,7 @@ test24: $(PROG) test24.ref
|
||||
echo name = value >> main.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
echo ' -o always_bcc=$$name' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -nC user >test24.tmp 2>&1
|
||||
diff test24.ref test24.tmp
|
||||
rm -f main.cf master.cf test24.tmp
|
||||
@ -348,6 +371,7 @@ test25: $(PROG) test25.ref
|
||||
echo name = value >> main.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
echo ' -o always_bcc=$$name' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -C service 2>&1 | grep whatevershebrings >test25.tmp
|
||||
diff test25.ref test25.tmp
|
||||
rm -f main.cf master.cf test25.tmp
|
||||
@ -361,6 +385,7 @@ test26: $(PROG) test26.ref
|
||||
echo name = value >> main.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
echo ' -o always_bcc=$$name' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . -C all >test26.tmp 2>&1
|
||||
diff test26.ref test26.tmp
|
||||
rm -f main.cf master.cf test26.tmp
|
||||
@ -372,6 +397,7 @@ test27: $(PROG) test27.ref
|
||||
echo name = value >> main.cf
|
||||
echo whatevershebrings unix - n n - 0 smtp >> master.cf
|
||||
echo ' -o always_bcc=$$name' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -c . -C all 2>&1 | grep whatevershebrings >test27.tmp
|
||||
diff test27.ref test27.tmp
|
||||
rm -f main.cf master.cf test27.tmp
|
||||
@ -392,6 +418,7 @@ test28: $(PROG) test28.ref
|
||||
echo ' -o body_checks=$$db:zz' >> master.cf
|
||||
echo 'zz_domain = whatever' >> main.cf
|
||||
echo 'aa_domain = whatever' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test28.tmp 2>&1
|
||||
diff test28.ref test28.tmp
|
||||
rm -f main.cf master.cf test28.tmp
|
||||
@ -416,6 +443,7 @@ test29: $(PROG) test29.ref
|
||||
echo 'memcachexx = proxy:memcache:memcachefoo' >> main.cf
|
||||
echo 'memcachefoo_domain = bar' >> main.cf
|
||||
echo 'memcachefoo_domainx = bar' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test29.tmp 2>&1
|
||||
diff test29.ref test29.tmp
|
||||
rm -f main.cf master.cf test29.tmp
|
||||
@ -432,6 +460,7 @@ test30: $(PROG) test30.ref
|
||||
echo ' -o bodyx_checks=$$p2' >> master.cf
|
||||
echo ' -oheader_checks=$$p3' >> master.cf
|
||||
echo ' -oheaderx_checks=$$p4' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nc . >test30.tmp 2>&1
|
||||
diff test30.ref test30.tmp
|
||||
rm -f main.cf master.cf test30.tmp
|
||||
@ -443,6 +472,7 @@ test31: $(PROG) test31.ref
|
||||
touch main.cf master.cf
|
||||
echo 'smtpd_helo_restrictions=whatever' >> main.cf
|
||||
echo 'smtpd_sender_restrictions=$$smtpd_helo_restrictions' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nxc . >test31.tmp 2>&1
|
||||
diff test31.ref test31.tmp
|
||||
rm -f main.cf master.cf test31.tmp
|
||||
@ -453,6 +483,7 @@ test32: $(PROG) test32.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo 'relay_domains=whatever' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -xc . fast_flush_domains >test32.tmp 2>&1
|
||||
diff test32.ref test32.tmp
|
||||
rm -f main.cf master.cf test32.tmp
|
||||
@ -464,6 +495,7 @@ test33: $(PROG) test33.ref
|
||||
touch main.cf master.cf
|
||||
echo 'mydestination=whatever' >> main.cf
|
||||
echo 'always_bcc=$$relay_domains' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -xc . always_bcc >test33.tmp 2>&1
|
||||
diff test33.ref test33.tmp
|
||||
rm -f main.cf master.cf test33.tmp
|
||||
@ -474,6 +506,7 @@ test34: $(PROG) test34.ref
|
||||
echo 'mydestination=whatever' >> main.cf
|
||||
echo 'process_name=xxx' >> main.cf
|
||||
echo 'process_id=yyy' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -xc . mydestination process_name >test34.tmp 2>&1
|
||||
diff test34.ref test34.tmp
|
||||
rm -f main.cf master.cf test34.tmp
|
||||
@ -485,6 +518,7 @@ test35: $(PROG) test35.ref
|
||||
echo ' -o body_checks=whatever' >> master.cf
|
||||
echo ' -o process_name=aaa' >> master.cf
|
||||
echo ' -o process_id=bbb' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -xc . process_name >test35.tmp 2>&1
|
||||
diff test35.ref test35.tmp
|
||||
rm -f main.cf master.cf test35.tmp
|
||||
@ -494,6 +528,7 @@ test36: $(PROG) test36.ref
|
||||
touch main.cf master.cf
|
||||
echo 'mydestination=$$virtual_mapx' >> main.cf
|
||||
echo 'virtual_alias_maps=$$virtual_maps' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nxc . >test36.tmp 2>&1
|
||||
diff test36.ref test36.tmp
|
||||
rm -f main.cf master.cf test36.tmp
|
||||
@ -507,6 +542,7 @@ test37: $(PROG) test37.ref
|
||||
echo ' -o mydestination=$$xxx' >> master.cf
|
||||
echo ' -o always_bcc=$$aaa' >> master.cf
|
||||
echo ' -o aaa=ccc' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfxc . >test37.tmp 2>&1
|
||||
diff test37.ref test37.tmp
|
||||
rm -f main.cf master.cf test37.tmp
|
||||
@ -517,6 +553,7 @@ test39: $(PROG) test39.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc . '*'/unix >test39.tmp 2>&1
|
||||
diff test39.ref test39.tmp
|
||||
rm -f main.cf master.cf test39.tmp
|
||||
@ -528,6 +565,7 @@ test40: $(PROG) test40.ref
|
||||
echo ' -voaaa=bbb' >> master.cf
|
||||
echo ' -vo ccc=$$aaa' >> master.cf
|
||||
echo ' -v -oddd=$$ccc' >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfxc . '*'/unix >test40.tmp 2>&1
|
||||
diff test40.ref test40.tmp
|
||||
rm -f main.cf master.cf test40.tmp
|
||||
@ -538,6 +576,7 @@ test41: $(PROG) test41.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar unix - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test41.tmp 2>&1
|
||||
./$(PROG) -Mfc. >>test41.tmp 2>&1
|
||||
./$(PROG) -Pc . bar/unix/xxx=YYY bar/unix/aaa=BBB >>test41.tmp 2>&1
|
||||
@ -552,6 +591,7 @@ test42: $(PROG) test42.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar unix - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test42.tmp 2>&1
|
||||
./$(PROG) -Mfc. >>test42.tmp 2>&1
|
||||
./$(PROG) -Pc . >>test42.tmp 2>&1
|
||||
@ -566,6 +606,7 @@ test43: $(PROG) test43.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar unix - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Fc . bar/unix/chroot=y bar/unix/command='aa -stuffobb=cc dd' >test43.tmp 2>&1
|
||||
./$(PROG) -Mfc. >>test43.tmp 2>&1
|
||||
diff test43.ref test43.tmp
|
||||
@ -577,6 +618,7 @@ test44: $(PROG) test44.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar unix - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mc . bar/unix='xx inet - n n - 0 aa -stuffobb=cc dd' >test44.tmp 2>&1
|
||||
./$(PROG) -Mfc. >>test44.tmp 2>&1
|
||||
diff test44.ref test44.tmp
|
||||
@ -588,6 +630,7 @@ test45: $(PROG) test45.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar xxxx - n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test45.tmp 2>&1 || true
|
||||
diff test45.ref test45.tmp
|
||||
rm -f main.cf master.cf test45.tmp
|
||||
@ -598,6 +641,7 @@ test46: $(PROG) test46.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet X n n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test46.tmp 2>&1 || true
|
||||
diff test46.ref test46.tmp
|
||||
rm -f main.cf master.cf test46.tmp
|
||||
@ -608,6 +652,7 @@ test47: $(PROG) test47.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - X n - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test47.tmp 2>&1 || true
|
||||
diff test47.ref test47.tmp
|
||||
rm -f main.cf master.cf test47.tmp
|
||||
@ -618,6 +663,7 @@ test48: $(PROG) test48.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n X - 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test48.tmp 2>&1 || true
|
||||
diff test48.ref test48.tmp
|
||||
rm -f main.cf master.cf test48.tmp
|
||||
@ -628,6 +674,7 @@ test49: $(PROG) test49.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n X 0 other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test49.tmp 2>&1 || true
|
||||
diff test49.ref test49.tmp
|
||||
rm -f main.cf master.cf test49.tmp
|
||||
@ -638,6 +685,7 @@ test50: $(PROG) test50.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n - X other >> master.cf
|
||||
echo baz unix - n n - 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test50.tmp 2>&1 || true
|
||||
diff test50.ref test50.tmp
|
||||
rm -f main.cf master.cf test50.tmp
|
||||
@ -648,6 +696,7 @@ test51: $(PROG) test51.ref
|
||||
echo foo unix - n n -? 0 other >> master.cf
|
||||
echo bar inet - n n X? 0 other >> master.cf
|
||||
echo baz unix - n n 0? 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -Mfc. >test51.tmp 2>&1 || true
|
||||
diff test51.ref test51.tmp
|
||||
rm -f main.cf master.cf test51.tmp
|
||||
@ -658,6 +707,7 @@ test52: $(PROG) test52.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n 0 0 other >> master.cf
|
||||
echo baz unix - n n 0 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -MXc. bar/inet foo/unix xxx/yyy
|
||||
./$(PROG) -Mfc. >test52.tmp 2>&1 || true
|
||||
diff test52.ref test52.tmp
|
||||
@ -669,6 +719,7 @@ test53: $(PROG) test53.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n 0 0 other >> master.cf
|
||||
echo baz unix - n n 0 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -M#c. bar/inet xxx/yyy
|
||||
diff test53.ref master.cf
|
||||
rm -f main.cf master.cf test53.tmp
|
||||
@ -679,6 +730,7 @@ test54: $(PROG) test54.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n 0 0 other >> master.cf
|
||||
echo baz unix - n n 0 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -M#c. bar/inet foo/unix
|
||||
diff test54.ref master.cf
|
||||
rm -f main.cf master.cf test54.tmp
|
||||
@ -689,6 +741,7 @@ test55: $(PROG) test55.ref
|
||||
echo foo unix - n n - 0 other >> master.cf
|
||||
echo bar inet - n n 0 0 other >> master.cf
|
||||
echo baz unix - n n 0 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -M#c. bar/inet baz/unix
|
||||
diff test55.ref master.cf
|
||||
rm -f main.cf master.cf test55.tmp
|
||||
@ -701,10 +754,41 @@ test56: $(PROG) test56.ref
|
||||
echo " -o first" >> master.cf
|
||||
echo " -o second" >> master.cf
|
||||
echo baz unix - n n 0 0 other >> master.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -M#c. bar/inet xxx/yyy
|
||||
diff test56.ref master.cf
|
||||
rm -f main.cf master.cf test56.tmp
|
||||
|
||||
# Many more tests in util/mac_expand.in.
|
||||
|
||||
test57: $(PROG) test57.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo 'x = $${{1} == {2}?{error}:x-value}' >> main.cf
|
||||
echo 'y = y-value' >> main.cf
|
||||
echo 'bar = $${x?{$$y}:$$z}' >> main.cf
|
||||
echo 'baz = $${x?{$$z}:$$y}' >> main.cf
|
||||
echo 'foo = $$bar$$baz' >> main.cf
|
||||
echo 't1 = Postfix 2.11 $${{$${x?bug:x}} == {bug}?in}compatible' >> main.cf
|
||||
echo 't2 = $$t1' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
./$(PROG) -nxc. >test57.tmp 2>&1
|
||||
diff test57.ref test57.tmp
|
||||
rm -f main.cf master.cf test57.tmp
|
||||
|
||||
test58: $(PROG) test58.ref
|
||||
rm -f main.cf master.cf
|
||||
touch main.cf master.cf
|
||||
echo 'mydestination = foo bar pipemap:{ldap:xxx, memcache:yy} randmap:{xx' >> main.cf
|
||||
echo 'xxx_domain = foo' >> main.cf
|
||||
echo 'xxx_bogus = foo' >> main.cf
|
||||
echo 'yy_backup = bbb' >> main.cf
|
||||
echo 'yy_bogus = bbb' >> main.cf
|
||||
touch -t 197101010000 main.cf
|
||||
$(SHLIB_ENV) ./postconf -nc. >test58.tmp 2>&1 || true
|
||||
diff test58.ref test58.tmp
|
||||
rm -f main.cf master.cf test58.tmp
|
||||
|
||||
printfck: $(OBJS) $(PROG)
|
||||
rm -rf printfck
|
||||
mkdir printfck
|
||||
@ -812,6 +896,8 @@ postconf_dbms.o: ../../include/htable.h
|
||||
postconf_dbms.o: ../../include/mac_expand.h
|
||||
postconf_dbms.o: ../../include/mac_parse.h
|
||||
postconf_dbms.o: ../../include/mail_conf.h
|
||||
postconf_dbms.o: ../../include/mail_params.h
|
||||
postconf_dbms.o: ../../include/msg.h
|
||||
postconf_dbms.o: ../../include/myflock.h
|
||||
postconf_dbms.o: ../../include/name_code.h
|
||||
postconf_dbms.o: ../../include/split_at.h
|
||||
|
@ -268,25 +268,26 @@
|
||||
/* PostgreSQL database client. This is described in
|
||||
/* \fBpgsql_table\fR(5).
|
||||
/* .IP "\fBpipemap\fR (read-only)"
|
||||
/* A pipeline of lookup tables. Example:
|
||||
/* "\fBpipemap:\fI!type_1:name_1! ... !type_n:name_n\fR".
|
||||
/* A lookup table that constructs a pipeline of tables. Example:
|
||||
/* "\fBpipemap:{\fItype_1:name_1, ..., type_n:name_n\fB}\fR".
|
||||
/* Each "pipemap:" query is given to the first table. Each
|
||||
/* lookup result becomes the query for the next table in the
|
||||
/* pipeline, and the last table produces the final result.
|
||||
/* When any table lookup produces no result, the pipeline
|
||||
/* produces no result. The first ASCII character after "pipemap:"
|
||||
/* will be used as the separator between the lookup tables
|
||||
/* that follow (do not use space, ",", ":" or non-ASCII).
|
||||
/* produces no result. The first and last characters of the
|
||||
/* "pipemap:" table name must be "\fB{\fR" and "\fB}\fR".
|
||||
/* Within these, individual maps are separated with comma or
|
||||
/* whitespace.
|
||||
/* .IP "\fBproxy\fR"
|
||||
/* Postfix \fBproxymap\fR(8) client for shared access to Postfix
|
||||
/* databases. The table name syntax is \fItype\fB:\fIname\fR.
|
||||
/* .IP "\fBrandmap\fR (read-only)"
|
||||
/* An in-memory table that performs random selection. Example:
|
||||
/* "\fBrandmap:\fI!result_1! ... !result_n\fR". Each table query
|
||||
/* "\fBrandmap:{\fIresult_1, ..., result_n\fB}\fR". Each table query
|
||||
/* returns a random choice from the specified results. The first
|
||||
/* ASCII character after "randmap:" will be used as the separator
|
||||
/* between the results that follow (do not use space, ",", ":"
|
||||
/* or non-ASCII).
|
||||
/* and last characters of the "randmap:" table name must be
|
||||
/* "\fB{\fR" and "\fB}\fR". Within these, individual maps are
|
||||
/* separated with comma or whitespace.
|
||||
/* .IP "\fBregexp\fR (read-only)"
|
||||
/* A lookup table based on regular expressions. The file format
|
||||
/* is described in \fBregexp_table\fR(5).
|
||||
|
@ -288,7 +288,7 @@ extern char *pcf_expand_parameter_value(VSTRING *, int, const char *,
|
||||
/*
|
||||
* postconf_print.c.
|
||||
*/
|
||||
extern void pcf_print_line(VSTREAM *, int, const char *,...);
|
||||
extern void PRINTFLIKE(3, 4) pcf_print_line(VSTREAM *, int, const char *,...);
|
||||
|
||||
/*
|
||||
* postconf_unused.c.
|
||||
|
@ -223,12 +223,11 @@ static const char *pcf_check_mydomainname(void)
|
||||
return (domain);
|
||||
|
||||
/*
|
||||
* Use the hostname when it is not a FQDN ("foo"), or when the hostname
|
||||
* actually is a domain name ("foo.com").
|
||||
* Use a default domain when the hostname is not a FQDN ("foo").
|
||||
*/
|
||||
if (var_myhostname == 0)
|
||||
pcf_get_myhostname();
|
||||
if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0)
|
||||
if ((dot = strchr(var_myhostname, '.')) == 0)
|
||||
return (domain = DEF_MYDOMAIN);
|
||||
return (domain = mystrdup(dot + 1));
|
||||
}
|
||||
|
@ -54,10 +54,12 @@
|
||||
#include <split_at.h>
|
||||
#include <mac_expand.h>
|
||||
#include <dict.h>
|
||||
#include <msg.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_conf.h>
|
||||
#include <mail_params.h>
|
||||
#include <dict_proxy.h>
|
||||
#include <dict_ldap.h>
|
||||
#include <dict_mysql.h>
|
||||
@ -142,35 +144,31 @@ static const PCF_DBMS_INFO pcf_dbms_info[] = {
|
||||
0,
|
||||
};
|
||||
|
||||
/* pcf_register_dbms_parameters - look for database_type:prefix_name */
|
||||
/*
|
||||
* Pseudo-databases that wrap around other databases.
|
||||
*/
|
||||
static const char *pcf_multi_dbms_names[] = {
|
||||
"pipemap", "addr_pipemap", "unionmap", 0,
|
||||
};
|
||||
|
||||
void pcf_register_dbms_parameters(const char *param_value,
|
||||
/* pcf_register_dbms_helper - parse one possible database type:name */
|
||||
|
||||
static void pcf_register_dbms_helper(char *str_value,
|
||||
const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
|
||||
PCF_MASTER_ENT *local_scope)
|
||||
{
|
||||
const PCF_DBMS_INFO *dp;
|
||||
char *bufp;
|
||||
size_t len;
|
||||
char *db_type;
|
||||
char *prefix;
|
||||
static VSTRING *buffer = 0;
|
||||
static VSTRING *candidate = 0;
|
||||
const char **cpp;
|
||||
|
||||
/*
|
||||
* XXX This does not examine both sides of conditional macro expansion,
|
||||
* and may expand the "wrong" conditional macros. This is the best we can
|
||||
* do for legacy database configuration support.
|
||||
* Naive parsing. We don't really know if this substring specifies a
|
||||
* database or some other text.
|
||||
*/
|
||||
if (buffer == 0)
|
||||
buffer = vstring_alloc(100);
|
||||
bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
|
||||
local_scope);
|
||||
|
||||
/*
|
||||
* Naive parsing. We don't really know if the parameter specifies free
|
||||
* text or a list of databases.
|
||||
*/
|
||||
while ((db_type = mystrtok(&bufp, " ,\t\r\n")) != 0) {
|
||||
while ((db_type = mystrtokq(&str_value, " ,\t\r\n", "{}")) != 0) {
|
||||
|
||||
/*
|
||||
* Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
|
||||
@ -188,21 +186,62 @@ void pcf_register_dbms_parameters(const char *param_value,
|
||||
* local or global namespace.
|
||||
*/
|
||||
if (prefix != 0 && *prefix != '/' && *prefix != '.') {
|
||||
for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
|
||||
if (strcmp(db_type, dp->db_type) == 0) {
|
||||
for (cpp = dp->db_suffixes; *cpp; cpp++) {
|
||||
vstring_sprintf(candidate ? candidate :
|
||||
(candidate = vstring_alloc(30)),
|
||||
"%s_%s", prefix, *cpp);
|
||||
flag_parameter(STR(candidate),
|
||||
PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
|
||||
local_scope);
|
||||
if (*prefix == '{') {
|
||||
if ((len = balpar(prefix, "{}")) > 0) {
|
||||
prefix[len - 1] = 0;
|
||||
for (cpp = pcf_multi_dbms_names; *cpp; cpp++) {
|
||||
if (strcmp(db_type, *cpp) == 0) {
|
||||
pcf_register_dbms_helper(prefix + 1, flag_parameter,
|
||||
local_scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (local_scope)
|
||||
msg_warn("%s:%s: missing '}' in parameter value: \"%s:%s\"",
|
||||
MASTER_CONF_FILE, local_scope->name_space);
|
||||
else
|
||||
msg_warn("%s: missing '}' in parameter value: \"%s:%s\"",
|
||||
MAIN_CONF_FILE, db_type, prefix);
|
||||
}
|
||||
} else {
|
||||
for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
|
||||
if (strcmp(db_type, dp->db_type) == 0) {
|
||||
for (cpp = dp->db_suffixes; *cpp; cpp++) {
|
||||
vstring_sprintf(candidate ? candidate :
|
||||
(candidate = vstring_alloc(30)),
|
||||
"%s_%s", prefix, *cpp);
|
||||
flag_parameter(STR(candidate),
|
||||
PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
|
||||
local_scope);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* pcf_register_dbms_parameters - look for database_type:prefix_name */
|
||||
|
||||
void pcf_register_dbms_parameters(const char *param_value,
|
||||
const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
|
||||
PCF_MASTER_ENT *local_scope)
|
||||
{
|
||||
char *bufp;
|
||||
static VSTRING *buffer = 0;
|
||||
|
||||
/*
|
||||
* XXX This does not examine both sides of conditional macro expansion,
|
||||
* and may expand the "wrong" conditional macros. This is the best we can
|
||||
* do for legacy database configuration support.
|
||||
*/
|
||||
if (buffer == 0)
|
||||
buffer = vstring_alloc(100);
|
||||
bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
|
||||
local_scope);
|
||||
pcf_register_dbms_helper(bufp, flag_parameter, local_scope);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
10
postfix/src/postconf/test57.ref
Normal file
10
postfix/src/postconf/test57.ref
Normal file
@ -0,0 +1,10 @@
|
||||
./postconf: warning: ./main.cf: undefined parameter: z
|
||||
./postconf: warning: ./main.cf: undefined parameter: z
|
||||
bar = y-value
|
||||
baz =
|
||||
config_directory = .
|
||||
t1 = Postfix 2.11 compatible
|
||||
x = x-value
|
||||
y = y-value
|
||||
./postconf: warning: ./main.cf: unused parameter: t2=$t1
|
||||
./postconf: warning: ./main.cf: unused parameter: foo=$bar$baz
|
7
postfix/src/postconf/test58.ref
Normal file
7
postfix/src/postconf/test58.ref
Normal file
@ -0,0 +1,7 @@
|
||||
./postconf: warning: main.cf: missing '}' in parameter value: "randmap:{xx"
|
||||
config_directory = .
|
||||
mydestination = foo bar pipemap:{ldap:xxx, memcache:yy} randmap:{xx
|
||||
xxx_domain = foo
|
||||
yy_backup = bbb
|
||||
./postconf: warning: ./main.cf: unused parameter: yy_bogus=bbb
|
||||
./postconf: warning: ./main.cf: unused parameter: xxx_bogus=foo
|
@ -651,6 +651,7 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
|
||||
static void post_jail_init(char *service_name, char **unused_argv)
|
||||
{
|
||||
const char *sep = ", \t\r\n";
|
||||
const char *parens = "{}";
|
||||
char *saved_filter;
|
||||
char *bp;
|
||||
char *type_name;
|
||||
@ -679,7 +680,7 @@ static void post_jail_init(char *service_name, char **unused_argv)
|
||||
saved_filter = bp = mystrdup(proxy_writer ? var_proxy_write_maps :
|
||||
var_proxy_read_maps);
|
||||
proxy_auth_maps = htable_create(13);
|
||||
while ((type_name = mystrtok(&bp, sep)) != 0) {
|
||||
while ((type_name = mystrtokq(&bp, sep, parens)) != 0) {
|
||||
if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
|
||||
continue;
|
||||
do {
|
||||
|
@ -497,7 +497,7 @@ static ARGV *smtpd_check_parse(int flags, const char *checks)
|
||||
#define SMTPD_CHECK_PARSE_MAPS (1<<1)
|
||||
#define SMTPD_CHECK_PARSE_ALL (~0)
|
||||
|
||||
while ((name = mystrtok(&bp, RESTRICTION_SEPARATORS)) != 0) {
|
||||
while ((name = mystrtokq(&bp, RESTRICTION_SEPARATORS, "{}")) != 0) {
|
||||
argv_add(argv, name, (char *) 0);
|
||||
if ((flags & SMTPD_CHECK_PARSE_POLICY)
|
||||
&& last && strcasecmp(last, CHECK_POLICY_SERVICE) == 0)
|
||||
@ -1044,10 +1044,11 @@ static int reject_unknown_client(SMTPD_STATE *state)
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s %s", myname, state->name, state->addr);
|
||||
|
||||
/* RFC 7372: Email Authentication Status Codes. */
|
||||
if (state->name_status != SMTPD_PEER_CODE_OK)
|
||||
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
||||
state->name_status >= SMTPD_PEER_CODE_PERM ?
|
||||
var_unk_client_code : 450, "4.7.1",
|
||||
var_unk_client_code : 450, "4.7.25",
|
||||
"Client host rejected: cannot find your hostname, [%s]",
|
||||
state->addr));
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
@ -2437,7 +2438,7 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
*/
|
||||
#define ADDROF(x) ((char *) &(x))
|
||||
|
||||
restrictions = argv_split(value, RESTRICTION_SEPARATORS);
|
||||
restrictions = argv_splitq(value, RESTRICTION_SEPARATORS, "{}");
|
||||
memcpy(ADDROF(savebuf), ADDROF(smtpd_check_buf), sizeof(savebuf));
|
||||
status = setjmp(smtpd_check_buf);
|
||||
if (status != 0) {
|
||||
@ -3940,7 +3941,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
SMTPD_NAME_CLIENT, def_acl);
|
||||
} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_ACL, &cpp)) {
|
||||
status = check_namadr_access(state, *cpp, state->reverse_name, state->addr,
|
||||
FULL, &found, state->namaddr,
|
||||
FULL, &found, state->reverse_name,
|
||||
SMTPD_NAME_REV_CLIENT, def_acl);
|
||||
forbid_whitelist(state, name, status, state->reverse_name);
|
||||
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
|
||||
@ -4030,21 +4031,21 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_NS_ACL, &cpp)) {
|
||||
if (strcasecmp(state->reverse_name, "unknown") != 0) {
|
||||
status = check_server_access(state, *cpp, state->reverse_name,
|
||||
T_NS, state->namaddr,
|
||||
T_NS, state->reverse_name,
|
||||
SMTPD_NAME_REV_CLIENT, def_acl);
|
||||
forbid_whitelist(state, name, status, state->reverse_name);
|
||||
}
|
||||
} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_MX_ACL, &cpp)) {
|
||||
if (strcasecmp(state->reverse_name, "unknown") != 0) {
|
||||
status = check_server_access(state, *cpp, state->reverse_name,
|
||||
T_MX, state->namaddr,
|
||||
T_MX, state->reverse_name,
|
||||
SMTPD_NAME_REV_CLIENT, def_acl);
|
||||
forbid_whitelist(state, name, status, state->reverse_name);
|
||||
}
|
||||
} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_A_ACL, &cpp)) {
|
||||
if (strcasecmp(state->reverse_name, "unknown") != 0) {
|
||||
status = check_server_access(state, *cpp, state->reverse_name,
|
||||
T_A, state->namaddr,
|
||||
T_A, state->reverse_name,
|
||||
SMTPD_NAME_REV_CLIENT, def_acl);
|
||||
forbid_whitelist(state, name, status, state->reverse_name);
|
||||
}
|
||||
|
@ -200,22 +200,23 @@ static void disconnect(SINK_STATE *state)
|
||||
static void connect_event(int unused_event, char *context)
|
||||
{
|
||||
int sock = CAST_CHAR_PTR_TO_INT(context);
|
||||
struct sockaddr sa;
|
||||
SOCKADDR_SIZE len = sizeof(sa);
|
||||
struct sockaddr_storage ss;
|
||||
SOCKADDR_SIZE len = sizeof(ss);
|
||||
struct sockaddr *sa = (struct sockaddr *) &ss;
|
||||
SINK_STATE *state;
|
||||
int fd;
|
||||
|
||||
if ((fd = accept(sock, &sa, &len)) >= 0) {
|
||||
if ((fd = accept(sock, sa, &len)) >= 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("connect (%s)",
|
||||
#ifdef AF_LOCAL
|
||||
sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
|
||||
sa->sa_family == AF_LOCAL ? "AF_LOCAL" :
|
||||
#else
|
||||
sa.sa_family == AF_UNIX ? "AF_UNIX" :
|
||||
sa->sa_family == AF_UNIX ? "AF_UNIX" :
|
||||
#endif
|
||||
sa.sa_family == AF_INET ? "AF_INET" :
|
||||
sa->sa_family == AF_INET ? "AF_INET" :
|
||||
#ifdef AF_INET6
|
||||
sa.sa_family == AF_INET6 ? "AF_INET6" :
|
||||
sa->sa_family == AF_INET6 ? "AF_INET6" :
|
||||
#endif
|
||||
"unknown protocol family");
|
||||
non_blocking(fd, NON_BLOCKING);
|
||||
|
@ -1298,31 +1298,32 @@ static void disconnect(SINK_STATE *state)
|
||||
|
||||
static void connect_event(int unused_event, char *unused_context)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
SOCKADDR_SIZE len = sizeof(sa);
|
||||
struct sockaddr_storage ss;
|
||||
SOCKADDR_SIZE len = sizeof(ss);
|
||||
struct sockaddr *sa = (struct sockaddr *) &ss;
|
||||
SINK_STATE *state;
|
||||
int fd;
|
||||
|
||||
if ((fd = sane_accept(sock, &sa, &len)) >= 0) {
|
||||
if ((fd = sane_accept(sock, sa, &len)) >= 0) {
|
||||
/* Safety: limit the number of open sockets and capture files. */
|
||||
if (++client_count == max_client_count)
|
||||
event_disable_readwrite(sock);
|
||||
state = (SINK_STATE *) mymalloc(sizeof(*state));
|
||||
if (strchr((char *) proto_info->sa_family_list, sa.sa_family))
|
||||
SOCKADDR_TO_HOSTADDR(&sa, len, &state->client_addr,
|
||||
(MAI_SERVPORT_STR *) 0, sa.sa_family);
|
||||
if (strchr((char *) proto_info->sa_family_list, sa->sa_family))
|
||||
SOCKADDR_TO_HOSTADDR(sa, len, &state->client_addr,
|
||||
(MAI_SERVPORT_STR *) 0, sa->sa_family);
|
||||
else
|
||||
strncpy(state->client_addr.buf, "local", sizeof("local"));
|
||||
if (msg_verbose)
|
||||
msg_info("connect (%s %s)",
|
||||
#ifdef AF_LOCAL
|
||||
sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
|
||||
sa->sa_family == AF_LOCAL ? "AF_LOCAL" :
|
||||
#else
|
||||
sa.sa_family == AF_UNIX ? "AF_UNIX" :
|
||||
sa->sa_family == AF_UNIX ? "AF_UNIX" :
|
||||
#endif
|
||||
sa.sa_family == AF_INET ? "AF_INET" :
|
||||
sa->sa_family == AF_INET ? "AF_INET" :
|
||||
#ifdef AF_INET6
|
||||
sa.sa_family == AF_INET6 ? "AF_INET6" :
|
||||
sa->sa_family == AF_INET6 ? "AF_INET6" :
|
||||
#endif
|
||||
"unknown protocol family",
|
||||
state->client_addr.buf);
|
||||
@ -1340,7 +1341,7 @@ static void connect_event(int unused_event, char *unused_context)
|
||||
state->delayed_args = 0;
|
||||
/* Initialize file capture attributes. */
|
||||
#ifdef AF_INET6
|
||||
if (sa.sa_family == AF_INET6)
|
||||
if (sa->sa_family == AF_INET6)
|
||||
state->addr_prefix = "ipv6:";
|
||||
else
|
||||
#endif
|
||||
|
@ -38,7 +38,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
|
||||
dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \
|
||||
dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c \
|
||||
poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \
|
||||
valid_utf8_hostname.c midna.c
|
||||
valid_utf8_hostname.c midna.c argv_splitq.c balpar.c
|
||||
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
|
||||
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
|
||||
@ -78,7 +78,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \
|
||||
dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o \
|
||||
poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \
|
||||
valid_utf8_hostname.o midna.o
|
||||
valid_utf8_hostname.o midna.o argv_splitq.o balpar.o
|
||||
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
|
||||
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
|
||||
# otherwise it sets the PLUGIN_* macros.
|
||||
@ -763,6 +763,14 @@ argv_split.o: stringops.h
|
||||
argv_split.o: sys_defs.h
|
||||
argv_split.o: vbuf.h
|
||||
argv_split.o: vstring.h
|
||||
argv_splitq.o: argv.h
|
||||
argv_splitq.o: argv_splitq.c
|
||||
argv_splitq.o: msg.h
|
||||
argv_splitq.o: mymalloc.h
|
||||
argv_splitq.o: stringops.h
|
||||
argv_splitq.o: sys_defs.h
|
||||
argv_splitq.o: vbuf.h
|
||||
argv_splitq.o: vstring.h
|
||||
attr_clnt.o: attr.h
|
||||
attr_clnt.o: attr_clnt.c
|
||||
attr_clnt.o: attr_clnt.h
|
||||
@ -847,6 +855,11 @@ auto_clnt.o: split_at.h
|
||||
auto_clnt.o: sys_defs.h
|
||||
auto_clnt.o: vbuf.h
|
||||
auto_clnt.o: vstream.h
|
||||
balpar.o: balpar.c
|
||||
balpar.o: stringops.h
|
||||
balpar.o: sys_defs.h
|
||||
balpar.o: vbuf.h
|
||||
balpar.o: vstring.h
|
||||
base32_code.o: base32_code.c
|
||||
base32_code.o: base32_code.h
|
||||
base32_code.o: msg.h
|
||||
@ -1156,6 +1169,7 @@ dict_random.o: msg.h
|
||||
dict_random.o: myflock.h
|
||||
dict_random.o: mymalloc.h
|
||||
dict_random.o: myrand.h
|
||||
dict_random.o: stringops.h
|
||||
dict_random.o: sys_defs.h
|
||||
dict_random.o: vbuf.h
|
||||
dict_random.o: vstream.h
|
||||
|
@ -35,6 +35,10 @@ extern ARGV *argv_split(const char *, const char *);
|
||||
extern ARGV *argv_split_count(const char *, const char *, ssize_t);
|
||||
extern ARGV *argv_split_append(ARGV *, const char *, const char *);
|
||||
|
||||
extern ARGV *argv_splitq(const char *, const char *, const char *);
|
||||
extern ARGV *argv_splitq_count(const char *, const char *, const char *, ssize_t);
|
||||
extern ARGV *argv_splitq_append(ARGV *, const char *, const char *, const char *);
|
||||
|
||||
#define ARGV_FAKE_BEGIN(fake_argv, arg) { \
|
||||
ARGV fake_argv; \
|
||||
char *__fake_argv_args__[2]; \
|
||||
|
118
postfix/src/util/argv_splitq.c
Normal file
118
postfix/src/util/argv_splitq.c
Normal file
@ -0,0 +1,118 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* argv_splitq 3
|
||||
/* SUMMARY
|
||||
/* string array utilities
|
||||
/* SYNOPSIS
|
||||
/* #include <argv.h>
|
||||
/*
|
||||
/* ARGV *argv_splitq(string, delim, parens)
|
||||
/* const char *string;
|
||||
/* const char *delim;
|
||||
/* const char *parens;
|
||||
/*
|
||||
/* ARGV *argv_splitq_count(string, delim, parens, count)
|
||||
/* const char *string;
|
||||
/* const char *delim;
|
||||
/* const char *parens;
|
||||
/* ssize_t count;
|
||||
/*
|
||||
/* ARGV *argv_splitq_append(argv, string, delim, parens)
|
||||
/* ARGV *argv;
|
||||
/* const char *string;
|
||||
/* const char *delim;
|
||||
/* const char *parens;
|
||||
/* DESCRIPTION
|
||||
/* argv_splitq() breaks up \fIstring\fR into tokens according
|
||||
/* to the delimiters specified in \fIdelim\fR, while avoiding
|
||||
/* splitting text between matching parentheses. The result is
|
||||
/* a null-terminated string array.
|
||||
/*
|
||||
/* argv_splitq_count() is like argv_splitq() but stops splitting
|
||||
/* input after at most \fIcount\fR -1 times and leaves the
|
||||
/* remainder, if any, in the last array element. It is an error
|
||||
/* to specify a count < 1.
|
||||
/*
|
||||
/* argv_splitq_append() performs the same operation as argv_splitq(),
|
||||
/* but appends the result to an existing string array.
|
||||
/* SEE ALSO
|
||||
/* mystrtokq(), safe string splitter.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: memory allocation problem.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System libraries. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "mymalloc.h"
|
||||
#include "stringops.h"
|
||||
#include "argv.h"
|
||||
#include "msg.h"
|
||||
|
||||
/* argv_splitq - split string into token array */
|
||||
|
||||
ARGV *argv_splitq(const char *string, const char *delim, const char *parens)
|
||||
{
|
||||
ARGV *argvp = argv_alloc(1);
|
||||
char *saved_string = mystrdup(string);
|
||||
char *bp = saved_string;
|
||||
char *arg;
|
||||
|
||||
while ((arg = mystrtokq(&bp, delim, parens)) != 0)
|
||||
argv_add(argvp, arg, (char *) 0);
|
||||
argv_terminate(argvp);
|
||||
myfree(saved_string);
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* argv_splitq_count - split string into token array */
|
||||
|
||||
ARGV *argv_splitq_count(const char *string, const char *delim,
|
||||
const char *parens, ssize_t count)
|
||||
{
|
||||
ARGV *argvp = argv_alloc(1);
|
||||
char *saved_string = mystrdup(string);
|
||||
char *bp = saved_string;
|
||||
char *arg;
|
||||
|
||||
if (count < 1)
|
||||
msg_panic("argv_splitq_count: bad count: %ld", (long) count);
|
||||
while (count-- > 1 && (arg = mystrtokq(&bp, delim, parens)) != 0)
|
||||
argv_add(argvp, arg, (char *) 0);
|
||||
if (*bp)
|
||||
bp += strspn(bp, delim);
|
||||
if (*bp)
|
||||
argv_add(argvp, bp, (char *) 0);
|
||||
argv_terminate(argvp);
|
||||
myfree(saved_string);
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* argv_splitq_append - split string into token array, append to array */
|
||||
|
||||
ARGV *argv_splitq_append(ARGV *argvp, const char *string, const char *delim,
|
||||
const char *parens)
|
||||
{
|
||||
char *saved_string = mystrdup(string);
|
||||
char *bp = saved_string;
|
||||
char *arg;
|
||||
|
||||
while ((arg = mystrtokq(&bp, delim, parens)) != 0)
|
||||
argv_add(argvp, arg, (char *) 0);
|
||||
argv_terminate(argvp);
|
||||
myfree(saved_string);
|
||||
return (argvp);
|
||||
}
|
56
postfix/src/util/balpar.c
Normal file
56
postfix/src/util/balpar.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* balpar 3
|
||||
/* SUMMARY
|
||||
/* determine length of string in parentheses
|
||||
/* SYNOPSIS
|
||||
/* #include <stringops.h>
|
||||
/*
|
||||
/* size_t balpar(string, parens)
|
||||
/* const char *string;
|
||||
/* const char *parens;
|
||||
/* DESCRIPTION
|
||||
/* balpar() determines the length of a string enclosed in
|
||||
/* the specified parentheses, zero in case of error.
|
||||
/* SEE ALSO
|
||||
/* A balpar() routine appears in Brian W. Kernighan, P.J. Plauger:
|
||||
/* "Software Tools", Addison-Wesley 1976. This function is different.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <stringops.h>
|
||||
|
||||
/* balpar - return length of {text} */
|
||||
|
||||
size_t balpar(const char *string, const char *parens)
|
||||
{
|
||||
const char *cp;
|
||||
int level;
|
||||
int ch;
|
||||
|
||||
if (*string != parens[0])
|
||||
return (0);
|
||||
for (level = 1, cp = string + 1; (ch = *cp) != 0; cp++) {
|
||||
if (ch == parens[1]) {
|
||||
if (--level == 0)
|
||||
return (cp - string + 1);
|
||||
} else if (ch == parens[0]) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
@ -244,7 +244,7 @@ void dict_test(int, char **);
|
||||
* functionality.
|
||||
*/
|
||||
extern int dict_allow_surrogate;
|
||||
extern DICT *dict_surrogate(const char *, const char *, int, int, const char *,...);
|
||||
extern DICT *PRINTFLIKE(5, 6) dict_surrogate(const char *, const char *, int, int, const char *,...);
|
||||
|
||||
/*
|
||||
* This name is reserved for matchlist error handling.
|
||||
|
@ -343,13 +343,7 @@ static const DICT_OPEN_INFO dict_open_info[] = {
|
||||
DICT_TYPE_SOCKMAP, dict_sockmap_open,
|
||||
DICT_TYPE_FAIL, dict_fail_open,
|
||||
DICT_TYPE_PIPE, dict_pipe_open,
|
||||
#ifdef DICT_TYPE_PIPE_LEGACY
|
||||
DICT_TYPE_PIPE_LEGACY, dict_pipe_open,
|
||||
#endif
|
||||
DICT_TYPE_RANDOM, dict_random_open,
|
||||
#ifdef DICT_TYPE_RANDOM_LEGACY
|
||||
DICT_TYPE_RANDOM_LEGACY, dict_random_open,
|
||||
#endif
|
||||
#ifndef USE_DYNAMIC_MAPS
|
||||
#ifdef HAS_PCRE
|
||||
DICT_TYPE_PCRE, dict_pcre_open,
|
||||
@ -530,6 +524,9 @@ DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(DICT_MAPNAMES_EXTEND_FN new_cb)
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
DEFINE_DICT_LMDB_MAP_SIZE;
|
||||
DEFINE_DICT_DB_CACHE_SIZE;
|
||||
|
||||
/*
|
||||
* Proof-of-concept test program.
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@
|
||||
/* int dict_flags;
|
||||
/* DESCRIPTION
|
||||
/* dict_pipe_open() opens a pipeline of one or more tables.
|
||||
/* Example: "\fBpipemap:\fI!type_1:name_1! ... !type_n:name_n\fR".
|
||||
/* Example: "\fBpipemap:{\fItype_1:name_1, ... ,type_n:name_n\fR}".
|
||||
/*
|
||||
/* Each "pipemap:" query is given to the first table. Each
|
||||
/* lookup result becomes the query for the next table in the
|
||||
@ -20,9 +20,9 @@
|
||||
/* When any table lookup produces no result, the pipeline
|
||||
/* produces no result.
|
||||
/*
|
||||
/* The first ASCII character after "pipemap:" will be used as
|
||||
/* the separator between the lookup tables that follow (do not
|
||||
/* use space, ",", ":" or non-ASCII).
|
||||
/* The first and last characters of the "pipemap:" table name
|
||||
/* must be '{' and '}'. Within these, individual maps are
|
||||
/* separated with comma or whitespace.
|
||||
/*
|
||||
/* The open_flags and dict_flags arguments are passed on to
|
||||
/* the underlying dictionaries.
|
||||
@ -114,7 +114,7 @@ DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags)
|
||||
DICT *dict;
|
||||
int match_flags = 0;
|
||||
struct DICT_OWNER aggr_owner;
|
||||
char delim[2];
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* Clarity first. Let the optimizer worry about redundant code.
|
||||
@ -135,32 +135,24 @@ DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags)
|
||||
open_flags, dict_flags,
|
||||
"%s:%s map requires O_RDONLY access mode",
|
||||
DICT_TYPE_PIPE, name));
|
||||
if (name[0] == ':')
|
||||
DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
|
||||
open_flags, dict_flags,
|
||||
"invalid list delimiter \"%c\" in \"%s:%s\"",
|
||||
name[0], DICT_TYPE_PIPE, name));
|
||||
|
||||
/*
|
||||
* Split the table name on the user-specified delimiter.
|
||||
* Split the table name into its constituent parts.
|
||||
*/
|
||||
delim[0] = name[0]; /* XXX ASCII delimiter */
|
||||
delim[1] = 0;
|
||||
saved_name = mystrdup(name + 1); /* XXX ASCII delimiter */
|
||||
if (*saved_name == 0)
|
||||
if ((len = balpar(name, "{}")) == 0 || name[len] != 0
|
||||
|| *(saved_name = mystrndup(name + 1, len - 2)) == 0)
|
||||
DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
|
||||
open_flags, dict_flags,
|
||||
"bad syntax: \"%s:%s\"; "
|
||||
"need \"%s:%stype:name%s...\"",
|
||||
"need \"%s:{type:name...}\"",
|
||||
DICT_TYPE_PIPE, name,
|
||||
DICT_TYPE_PIPE, delim, delim));
|
||||
DICT_TYPE_PIPE));
|
||||
|
||||
/*
|
||||
* The least-trusted table in the pipeline determines the over-all trust
|
||||
* level. The first table determines the pattern-matching flags.
|
||||
*/
|
||||
DICT_OWNER_AGGREGATE_INIT(aggr_owner);
|
||||
argv = argv_split(saved_name, delim);
|
||||
argv = argv_splitq(saved_name, ", \t\r\n", "{}");
|
||||
for (cpp = argv->argv; (dict_type_name = *cpp) != 0; cpp++) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s", myname, dict_type_name);
|
||||
@ -168,9 +160,9 @@ DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags)
|
||||
DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
|
||||
open_flags, dict_flags,
|
||||
"bad syntax: \"%s:%s\"; "
|
||||
"need \"%s:%stype:name%s...\"",
|
||||
"need \"%s:{type:name...}\"",
|
||||
DICT_TYPE_PIPE, name,
|
||||
DICT_TYPE_PIPE, delim, delim));
|
||||
DICT_TYPE_PIPE));
|
||||
if ((dict = dict_handle(dict_type_name)) == 0)
|
||||
dict = dict_open(dict_type_name, open_flags, dict_flags);
|
||||
dict_register(dict_type_name, dict);
|
||||
|
@ -21,10 +21,6 @@
|
||||
*/
|
||||
#define DICT_TYPE_PIPE "pipemap"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
#define DICT_TYPE_PIPE_LEGACY "pipeline"
|
||||
#endif
|
||||
|
||||
extern DICT *dict_pipe_open(const char *, int, int);
|
||||
|
||||
/* LICENSE
|
||||
|
@ -12,14 +12,14 @@
|
||||
/* int dict_flags;
|
||||
/* DESCRIPTION
|
||||
/* dict_random_open() opens an in-memory, read-only, table.
|
||||
/* Example: "\fBrandmap:\fI!result_1! ... !result_n\fR".
|
||||
/* Example: "\fBrandmap:{\fIresult_1, ... ,result_n}\fR".
|
||||
/*
|
||||
/* Each table query returns a random choice from the specified
|
||||
/* results. Other table access methods are not supported.
|
||||
/*
|
||||
/* The ASCII character after "randmap:" will be used as the
|
||||
/* separator between the results that follow (do not use space,
|
||||
/* ",", ":" or non-ASCII).
|
||||
/* The first and last characters of the "randmap:" table name
|
||||
/* must be '{' and '}'. Within these, individual maps are
|
||||
/* separated with comma or whitespace.
|
||||
/* SEE ALSO
|
||||
/* dict(3) generic dictionary manager
|
||||
/* LICENSE
|
||||
@ -43,6 +43,7 @@
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <myrand.h>
|
||||
#include <stringops.h>
|
||||
#include <dict_random.h>
|
||||
|
||||
/* Application-specific. */
|
||||
@ -80,7 +81,7 @@ DICT *dict_random_open(const char *name, int open_flags, int dict_flags)
|
||||
{
|
||||
DICT_RANDOM *dict_random;
|
||||
char *saved_name = 0;
|
||||
char delim[2];
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* Clarity first. Let the optimizer worry about redundant code.
|
||||
@ -101,17 +102,16 @@ DICT *dict_random_open(const char *name, int open_flags, int dict_flags)
|
||||
DICT_TYPE_RANDOM, name));
|
||||
|
||||
/*
|
||||
* Split the name on the user-specified delimiter.
|
||||
* Split the name name into its constituent parts.
|
||||
*/
|
||||
delim[0] = name[0]; /* XXX ASCII delimiter */
|
||||
delim[1] = 0;
|
||||
saved_name = mystrdup(name + 1); /* XXX ASCII delimiter */
|
||||
if (*saved_name == 0)
|
||||
if ((len = balpar(name, "{}")) == 0 || name[len] != 0
|
||||
|| *(saved_name = mystrndup(name + 1, len - 2)) == 0)
|
||||
DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name,
|
||||
open_flags, dict_flags,
|
||||
"bad syntax: \"%s:%s\"; need \"%s:%svalue%s...\"",
|
||||
"bad syntax: \"%s:%s\"; "
|
||||
"need \"%s:{type:name...}\"",
|
||||
DICT_TYPE_RANDOM, name,
|
||||
DICT_TYPE_RANDOM, delim, delim));
|
||||
DICT_TYPE_RANDOM));
|
||||
|
||||
/*
|
||||
* Bundle up the result.
|
||||
@ -121,9 +121,9 @@ DICT *dict_random_open(const char *name, int open_flags, int dict_flags)
|
||||
dict_random->dict.lookup = dict_random_lookup;
|
||||
dict_random->dict.close = dict_random_close;
|
||||
dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN;
|
||||
dict_random->replies = argv_split(saved_name, delim);
|
||||
dict_random->replies = argv_splitq(saved_name, ", \t\r\n", "{}");
|
||||
dict_random->dict.owner.status = DICT_OWNER_TRUSTED;
|
||||
dict_random->dict.owner.uid = 0;
|
||||
|
||||
DICT_RANDOM_RETURN(DICT_DEBUG(&dict_random->dict));
|
||||
DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict));
|
||||
}
|
||||
|
@ -21,10 +21,6 @@
|
||||
*/
|
||||
#define DICT_TYPE_RANDOM "randmap"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
#define DICT_TYPE_RANDOM_LEGACY "random"
|
||||
#endif
|
||||
|
||||
extern DICT *dict_random_open(const char *, int, int);
|
||||
|
||||
/* LICENSE
|
||||
|
@ -24,9 +24,6 @@
|
||||
#include <dict_lmdb.h>
|
||||
#include <dict_db.h>
|
||||
|
||||
DEFINE_DICT_LMDB_MAP_SIZE;
|
||||
DEFINE_DICT_DB_CACHE_SIZE;
|
||||
|
||||
static NORETURN usage(char *myname)
|
||||
{
|
||||
msg_fatal("usage: %s type:file read|write|create [flags...]", myname);
|
||||
|
@ -14,46 +14,70 @@
|
||||
/* const char *lookup(const char *key, int mode, char *context)
|
||||
/* char *context;
|
||||
/* DESCRIPTION
|
||||
/* This module implements parameter-less macro expansions, both
|
||||
/* conditional and unconditional, and both recursive and non-recursive.
|
||||
/* This module implements parameter-less named attribute
|
||||
/* expansions, both conditional and unconditional. As of Postfix
|
||||
/* 2.12 this code supports logical expression evaluation.
|
||||
/*
|
||||
/* In this text, an attribute is considered "undefined" when its value
|
||||
/* is a null pointer. Otherwise, the attribute is considered "defined"
|
||||
/* and is expected to have as value a null-terminated string.
|
||||
/*
|
||||
/* The following expansions are implemented:
|
||||
/* .IP "$name, ${name}, $(name)"
|
||||
/* Unconditional expansion. If the named attribute value is non-empty, the
|
||||
/* expansion is the value of the named attribute, optionally subjected
|
||||
/* to further $name expansions. Otherwise, the expansion is empty.
|
||||
/* .IP "${name?text}, $(name?text)"
|
||||
/* Conditional expansion. If the named attribute value is non-empty, the
|
||||
/* expansion is the given text, subjected to another iteration of
|
||||
/* $name expansion. Otherwise, the expansion is empty.
|
||||
/* .IP "${name:text}, $(name:text)"
|
||||
/* Conditional expansion. If the attribute value is empty or undefined,
|
||||
/* the expansion is the given text, subjected to another iteration
|
||||
/* of $name expansion. Otherwise, the expansion is empty.
|
||||
/* .PP
|
||||
/* In the text below, the legacy form $(...) is equivalent to
|
||||
/* ${...}. The legacy form $(...) may eventually disappear
|
||||
/* from documentation.
|
||||
/*
|
||||
/* The following substitutions are supported:
|
||||
/* .IP "$name, ${name}"
|
||||
/* Unconditional attribute-based substition. The result is the
|
||||
/* named attribute value (empty if the attribute is not defined)
|
||||
/* after optional further named attribute substitution.
|
||||
/* .IP "${name?text}, ${name?{text}}"
|
||||
/* Conditional attribute-based substition. If the named attribute
|
||||
/* value is non-empty, the result is the given text, after
|
||||
/* named attribute expansion and logical expression evaluation.
|
||||
/* Otherwise, the result is empty. Whitespace before or after
|
||||
/* {text} is ignored.
|
||||
/* .IP "${name:text}, ${name:{text}}"
|
||||
/* Conditional attribute-based substition. If the attribute
|
||||
/* value is empty or undefined, the expansion is the given
|
||||
/* text, after named attribute expansion and logical expression
|
||||
/* evaluation. Otherwise, the result is empty. Whitespace
|
||||
/* before or after {text} is ignored.
|
||||
/* .IP "${name?{text1}:{text2}}, ${name?{text1}:text2}"
|
||||
/* Conditional attribute-based substition. If the named attribute
|
||||
/* value is non-empty, the result is text1. Otherwise, the
|
||||
/* result is text2. In both cases the result is subject to
|
||||
/* named attribute expansion and logical expression evaluation.
|
||||
/* Whitespace before or after {text1} or {text2} is ignored.
|
||||
/* .IP "${{text1} == ${text2} ? {text3} : {text4}}"
|
||||
/* .IP "${{text1} != ${text2} ? {text3} : {text4}}"
|
||||
/* Logical expression-based substition. First, the content
|
||||
/* of {text1} and ${text2} is subjected to named attribute and
|
||||
/* logical expression-based substitution. Next, the logical
|
||||
/* expression is evaluated. If it evaluates to "true", the
|
||||
/* result is the content of {text3}, otherwise it is the content
|
||||
/* of {text4}, after named attribute and logical expression-based
|
||||
/* substitution.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP result
|
||||
/* Storage for the result of expansion. The result is truncated
|
||||
/* upon entry.
|
||||
/* Storage for the result of expansion. By default, the result
|
||||
/* is truncated upon entry.
|
||||
/* .IP pattern
|
||||
/* The string to be expanded.
|
||||
/* .IP flags
|
||||
/* Bit-wise OR of zero or more of the following:
|
||||
/* .RS
|
||||
/* .IP MAC_EXP_FLAG_RECURSE
|
||||
/* Expand macros in lookup results. This should never be done with
|
||||
/* data whose origin is untrusted.
|
||||
/* Expand attributes in lookup results. This should never be
|
||||
/* done with data whose origin is untrusted.
|
||||
/* .IP MAC_EXP_FLAG_APPEND
|
||||
/* Append text to the result buffer without truncating it.
|
||||
/* .IP MAC_EXP_FLAG_SCAN
|
||||
/* Invoke the call-back function for each macro name in the input
|
||||
/* string, including macro names in the values of conditional
|
||||
/* expressions. Do not expand macros, and do not write to the
|
||||
/* result argument.
|
||||
/* Scan the input for named attributes, including named
|
||||
/* attributes in all conditional result values. Do not expand
|
||||
/* named attributes, and do not truncate or write to the result
|
||||
/* argument.
|
||||
/* .IP MAC_EXP_FLAG_PRINTABLE
|
||||
/* Use the printable() function instead of \fIfilter\fR.
|
||||
/* .PP
|
||||
@ -73,14 +97,14 @@
|
||||
/* Caller context that is passed on to the attribute lookup routine.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: out of memory. Warnings: syntax errors, unreasonable
|
||||
/* macro nesting.
|
||||
/* recursion depth.
|
||||
/*
|
||||
/* The result value is the binary OR of zero or more of the following:
|
||||
/* .IP MAC_PARSE_ERROR
|
||||
/* A syntax error was found in \fBpattern\fR, or some macro had
|
||||
/* A syntax error was found in \fBpattern\fR, or some attribute had
|
||||
/* an unreasonable nesting depth.
|
||||
/* .IP MAC_PARSE_UNDEF
|
||||
/* A macro was expanded but its value not defined.
|
||||
/* An attribute was expanded but its value was not defined.
|
||||
/* SEE ALSO
|
||||
/* mac_parse(3) locate macro references in string.
|
||||
/* LICENSE
|
||||
@ -106,6 +130,7 @@
|
||||
#include <vstring.h>
|
||||
#include <mymalloc.h>
|
||||
#include <stringops.h>
|
||||
#include <name_code.h>
|
||||
#include <mac_parse.h>
|
||||
#include <mac_expand.h>
|
||||
|
||||
@ -120,95 +145,366 @@ typedef struct {
|
||||
char *context; /* caller context */
|
||||
int status; /* findings */
|
||||
int level; /* nesting level */
|
||||
} MAC_EXP;
|
||||
} MAC_EXP_CONTEXT;
|
||||
|
||||
/*
|
||||
* Support for logical expressions.
|
||||
*
|
||||
* As of Postfix 2.2, ${attr-name?result} or ${attr-name:result} return the
|
||||
* result respectively when the parameter value is non-empty, or when the
|
||||
* parameter value is undefined or empty; support for the ternary ?:
|
||||
* operator was anticipated, but not implemented for 10 years.
|
||||
*
|
||||
* To make ${logical-expr?result} and ${logical-expr:result} work as expected
|
||||
* without breaking the way that ? and : work, logical expressions evaluate
|
||||
* to a non-empty or empty value. It does not matter what non-empty value we
|
||||
* use for TRUE. However we must not use the undefined (null pointer) value
|
||||
* for FALSE - that would raise the MAC_PARSE_UNDEF flag.
|
||||
*
|
||||
* The value of a logical expression can be exposed with ${logical-expr}, i.e.
|
||||
* a logical expression that is not followed by ? or : conditional
|
||||
* expansion.
|
||||
*/
|
||||
#define MAC_EXP_BVAL_TRUE "true"
|
||||
#define MAC_EXP_BVAL_FALSE ""
|
||||
|
||||
/*
|
||||
* Relational operator. For now, we test only for (in)equality.
|
||||
*/
|
||||
#define MAC_EXP_OP_STR_EQ "=="
|
||||
#define MAC_EXP_OP_STR_NE "!="
|
||||
#define MAC_EXP_OP_STR_ANY "\"" MAC_EXP_OP_STR_EQ \
|
||||
"\" or \"" MAC_EXP_OP_STR_NE "\""
|
||||
|
||||
#define MAC_EXP_OP_TOK_NONE 0
|
||||
#define MAC_EXP_OP_TOK_EQ 1
|
||||
#define MAC_EXP_OP_TOK_NE 2
|
||||
|
||||
static const NAME_CODE mac_exp_op_table[] =
|
||||
{
|
||||
MAC_EXP_OP_STR_EQ, MAC_EXP_OP_TOK_EQ,
|
||||
MAC_EXP_OP_STR_NE, MAC_EXP_OP_TOK_NE,
|
||||
0, MAC_EXP_OP_TOK_NONE,
|
||||
};
|
||||
|
||||
/*
|
||||
* The whitespace separator set.
|
||||
*/
|
||||
#define MAC_EXP_WHITESPACE " \t\r\n"
|
||||
|
||||
/* mac_exp_parse_error - report parse error, set error flag, return status */
|
||||
|
||||
static int PRINTFLIKE(2, 3) mac_exp_parse_error(MAC_EXP_CONTEXT *mc,
|
||||
const char *fmt,...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vmsg_warn(fmt, ap);
|
||||
va_end(ap);
|
||||
return (mc->status |= MAC_PARSE_ERROR);
|
||||
};
|
||||
|
||||
/* MAC_EXP_ERR_RETURN - report parse error, set error flag, return status */
|
||||
|
||||
#define MAC_EXP_ERR_RETURN(mc, fmt, ...) do { \
|
||||
return (mac_exp_parse_error(mc, fmt, __VA_ARGS__)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Postfix 2.12 introduces support for {text} operands. Only with these do
|
||||
* we support the ternary ?: operator and logical operators.
|
||||
*
|
||||
* We cannot support operators in random text, because that would break Postfix
|
||||
* 2.11 compatibility. For example, with the expression "${name?value}", the
|
||||
* value is random text that may contain ':', '?', '{' and '}' characters.
|
||||
* In particular, with Postfix 2.2 .. 2.11, "${name??foo:{b}ar}" evaluates
|
||||
* to "??foo:{b}ar" or empty. There are explicit tests in this directory and
|
||||
* the postconf directory to ensure that Postfix 2.11 compatibility is
|
||||
* maintained.
|
||||
*
|
||||
* Ideally, future Postfix configurations enclose random text operands inside
|
||||
* {} braces. These allow whitespace around operands, which improves
|
||||
* readability.
|
||||
*/
|
||||
|
||||
/* MAC_EXP_FIND_LEFT_CURLY - skip over whitespace to '{', advance read ptr */
|
||||
|
||||
#define MAC_EXP_FIND_LEFT_CURLY(len, cp) \
|
||||
((cp[len = strspn(cp, MAC_EXP_WHITESPACE)] == '{') ? \
|
||||
(cp += len) : 0)
|
||||
|
||||
/* mac_exp_extract_curly_payload - balance {}, skip whitespace, return payload */
|
||||
|
||||
static char *mac_exp_extract_curly_payload(MAC_EXP_CONTEXT *mc, char **bp)
|
||||
{
|
||||
char *payload;
|
||||
char *cp;
|
||||
int level;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* Extract the payload and balance the {}. The caller is expected to skip
|
||||
* leading whitespace before the {. See MAC_EXP_FIND_LEFT_CURLY().
|
||||
*/
|
||||
for (level = 1, cp = *bp, payload = ++cp; /* see below */ ; cp++) {
|
||||
if ((ch = *cp) == 0) {
|
||||
mac_exp_parse_error(mc, "unbalanced {} in attribute expression: "
|
||||
"\"%s\"",
|
||||
*bp);
|
||||
return (0);
|
||||
} else if (ch == '{') {
|
||||
level++;
|
||||
} else if (ch == '}') {
|
||||
if (--level <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*cp++ = 0;
|
||||
|
||||
/*
|
||||
* Skip trailing whitespace after }.
|
||||
*/
|
||||
*bp = cp + strspn(cp, MAC_EXP_WHITESPACE);
|
||||
return (payload);
|
||||
}
|
||||
|
||||
/* mac_exp_parse_logical - parse logical expression, advance read ptr */
|
||||
|
||||
static int mac_exp_parse_logical(MAC_EXP_CONTEXT *mc, const char **lookup,
|
||||
char **bp)
|
||||
{
|
||||
const char myname[] = "mac_exp_parse_logical";
|
||||
char *cp = *bp;
|
||||
VSTRING *left_op_buf;
|
||||
VSTRING *rite_op_buf;
|
||||
const char *left_op_strval;
|
||||
const char *rite_op_strval;
|
||||
char *op_strval;
|
||||
size_t op_len;
|
||||
int op_tokval;
|
||||
int op_result;
|
||||
size_t tmp_len;
|
||||
|
||||
/*
|
||||
* Left operand. The caller is expected to skip leading whitespace before
|
||||
* the {. See MAC_EXP_FIND_LEFT_CURLY().
|
||||
*/
|
||||
if ((left_op_strval = mac_exp_extract_curly_payload(mc, &cp)) == 0)
|
||||
return (mc->status);
|
||||
|
||||
/*
|
||||
* Operator. Todo: regexp operator.
|
||||
*/
|
||||
op_len = strspn(cp, "<>!=?+-*/~&|%"); /* for better diagnostics. */
|
||||
op_strval = mystrndup(cp, op_len);
|
||||
op_tokval = name_code(mac_exp_op_table, NAME_CODE_FLAG_NONE, op_strval);
|
||||
myfree(op_strval);
|
||||
if (op_tokval == MAC_EXP_OP_TOK_NONE)
|
||||
MAC_EXP_ERR_RETURN(mc, "%s expected at: \"...%s}>>>%.20s\"",
|
||||
MAC_EXP_OP_STR_ANY, left_op_strval, cp);
|
||||
cp += op_len;
|
||||
|
||||
/*
|
||||
* Right operand. Todo: syntax may depend on operator.
|
||||
*/
|
||||
if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp) == 0)
|
||||
MAC_EXP_ERR_RETURN(mc, "\"{expression}\" expected at: "
|
||||
"\"...{%s} %.*s>>>%.20s\"",
|
||||
left_op_strval, (int) op_len, op_strval, cp);
|
||||
if ((rite_op_strval = mac_exp_extract_curly_payload(mc, &cp)) == 0)
|
||||
return (mc->status);
|
||||
|
||||
/*
|
||||
* Evaluate the logical expression. Todo: regexp support.
|
||||
*/
|
||||
mc->status |=
|
||||
mac_expand(left_op_buf = vstring_alloc(100), left_op_strval,
|
||||
mc->flags, mc->filter, mc->lookup, mc->context);
|
||||
mc->status |=
|
||||
mac_expand(rite_op_buf = vstring_alloc(100), rite_op_strval,
|
||||
mc->flags, mc->filter, mc->lookup, mc->context);
|
||||
op_result =
|
||||
strcmp(vstring_str(left_op_buf), vstring_str(rite_op_buf));
|
||||
vstring_free(left_op_buf);
|
||||
vstring_free(rite_op_buf);
|
||||
if (mc->status & MAC_PARSE_ERROR)
|
||||
return (mc->status);
|
||||
|
||||
/*
|
||||
* Here, we fake up a non-empty or empty parameter value lookup result,
|
||||
* for compatibility with the historical code that looks named parameter
|
||||
* values.
|
||||
*/
|
||||
switch (op_tokval) {
|
||||
case MAC_EXP_OP_TOK_EQ:
|
||||
*lookup = op_result == 0 ?
|
||||
MAC_EXP_BVAL_TRUE : MAC_EXP_BVAL_FALSE;
|
||||
break;
|
||||
case MAC_EXP_OP_TOK_NE:
|
||||
*lookup = op_result != 0 ?
|
||||
MAC_EXP_BVAL_TRUE : MAC_EXP_BVAL_FALSE;
|
||||
break;
|
||||
default:
|
||||
msg_panic("%s: unknown macro operator code %d",
|
||||
myname, op_tokval);
|
||||
}
|
||||
*bp = cp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* mac_expand_callback - callback for mac_parse */
|
||||
|
||||
static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
|
||||
{
|
||||
MAC_EXP *mc = (MAC_EXP *) ptr;
|
||||
const char myname[] = "mac_expand_callback";
|
||||
MAC_EXP_CONTEXT *mc = (MAC_EXP_CONTEXT *) ptr;
|
||||
int lookup_mode;
|
||||
const char *text;
|
||||
const char *lookup;
|
||||
char *cp;
|
||||
int ch;
|
||||
ssize_t len;
|
||||
ssize_t res_len;
|
||||
ssize_t tmp_len;
|
||||
const char *res_iftrue;
|
||||
const char *res_iffalse;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (mc->level++ > 100) {
|
||||
msg_warn("unreasonable macro call nesting: \"%s\"", vstring_str(buf));
|
||||
mc->status |= MAC_PARSE_ERROR;
|
||||
}
|
||||
if (mc->level++ > 100)
|
||||
mac_exp_parse_error(mc, "unreasonable macro call nesting: \"%s\"",
|
||||
vstring_str(buf));
|
||||
if (mc->status & MAC_PARSE_ERROR)
|
||||
return (mc->status);
|
||||
|
||||
/*
|
||||
* $Name etc. reference.
|
||||
*
|
||||
* In order to support expansion of lookup results, we must save the lookup
|
||||
* result. We use the input buffer since it will not be needed anymore.
|
||||
* Named parameter or logical expression. In case of a syntax error,
|
||||
* return without doing damage, and issue a warning instead.
|
||||
*/
|
||||
if (type == MAC_PARSE_EXPR) {
|
||||
|
||||
cp = vstring_str(buf);
|
||||
|
||||
/*
|
||||
* Look for the ? or : delimiter. In case of a syntax error, return
|
||||
* without doing damage, and issue a warning instead.
|
||||
* Logical expression. If recursion is disabled, perform only one
|
||||
* level of $name expansion.
|
||||
*/
|
||||
for (cp = vstring_str(buf); /* void */ ; cp++) {
|
||||
if ((ch = *cp) == 0) {
|
||||
lookup_mode = MAC_EXP_MODE_USE;
|
||||
break;
|
||||
}
|
||||
if (ch == '?' || ch == ':') {
|
||||
*cp++ = 0;
|
||||
lookup_mode = MAC_EXP_MODE_TEST;
|
||||
break;
|
||||
}
|
||||
if (!ISALNUM(ch) && ch != '_') {
|
||||
msg_warn("macro name syntax error: \"%s\"", vstring_str(buf));
|
||||
mc->status |= MAC_PARSE_ERROR;
|
||||
if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
|
||||
if (mac_exp_parse_logical(mc, &lookup, &cp) != 0)
|
||||
return (mc->status);
|
||||
|
||||
/*
|
||||
* Look for the ? or : operator.
|
||||
*/
|
||||
if ((ch = *cp) != 0) {
|
||||
if (ch != '?' && ch != ':')
|
||||
MAC_EXP_ERR_RETURN(mc, "\"?\" or \":\" expected at: "
|
||||
"\"...}>>>%.20s\"", cp);
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the named parameter.
|
||||
* Named parameter.
|
||||
*/
|
||||
text = mc->lookup(vstring_str(buf), lookup_mode, mc->context);
|
||||
else {
|
||||
|
||||
/*
|
||||
* Look for the ? or : operator. In case of a syntax error,
|
||||
* return without doing damage, and issue a warning instead.
|
||||
*/
|
||||
for ( /* void */ ; /* void */ ; cp++) {
|
||||
if ((ch = *cp) == 0) {
|
||||
lookup_mode = MAC_EXP_MODE_USE;
|
||||
break;
|
||||
}
|
||||
if (ch == '?' || ch == ':') {
|
||||
*cp++ = 0;
|
||||
lookup_mode = MAC_EXP_MODE_TEST;
|
||||
break;
|
||||
}
|
||||
if (!ISALNUM(ch) && ch != '_') {
|
||||
MAC_EXP_ERR_RETURN(mc, "attribute name syntax error at: "
|
||||
"\"...%.*s>>>%.20s\"",
|
||||
(int) (cp - vstring_str(buf)),
|
||||
vstring_str(buf), cp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the named parameter. Todo: allow the lookup function
|
||||
* to specify if the result is safe for $name expanson.
|
||||
*/
|
||||
lookup = mc->lookup(vstring_str(buf), lookup_mode, mc->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the requested substitution.
|
||||
* Return the requested result. After parsing the result operand
|
||||
* following ?, we fall through to parse the result operand following
|
||||
* :. This is necessary with the ternary ?: operator: first, with
|
||||
* MAC_EXP_FLAG_SCAN to parse both result operands with mac_parse(),
|
||||
* and second, to find garbage after any result operand. Without
|
||||
* MAC_EXP_FLAG_SCAN the content of only one of the ?: result
|
||||
* operands will be parsed with mac_parse(); syntax errors in the
|
||||
* other operand will be missed.
|
||||
*/
|
||||
switch (ch) {
|
||||
case '?':
|
||||
if ((text != 0 && *text != 0) || (mc->flags & MAC_EXP_FLAG_SCAN))
|
||||
mac_parse(cp, mac_expand_callback, (char *) mc);
|
||||
break;
|
||||
if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
|
||||
if ((res_iftrue = mac_exp_extract_curly_payload(mc, &cp)) == 0)
|
||||
return (mc->status);
|
||||
} else {
|
||||
res_iftrue = cp;
|
||||
cp = ""; /* no left-over text */
|
||||
}
|
||||
if ((lookup != 0 && *lookup != 0) || (mc->flags & MAC_EXP_FLAG_SCAN))
|
||||
mc->status |= mac_parse(res_iftrue, mac_expand_callback,
|
||||
(char *) mc);
|
||||
if (*cp == 0) /* end of input, OK */
|
||||
break;
|
||||
if (*cp != ':') /* garbage */
|
||||
MAC_EXP_ERR_RETURN(mc, "\":\" expected at: "
|
||||
"\"...%s}>>>%.20s\"", res_iftrue, cp);
|
||||
cp += 1;
|
||||
/* FALLTHROUGH: do not remove, see comment above. */
|
||||
case ':':
|
||||
if (text == 0 || *text == 0 || (mc->flags & MAC_EXP_FLAG_SCAN))
|
||||
mac_parse(cp, mac_expand_callback, (char *) mc);
|
||||
if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
|
||||
if ((res_iffalse = mac_exp_extract_curly_payload(mc, &cp)) == 0)
|
||||
return (mc->status);
|
||||
} else {
|
||||
res_iffalse = cp;
|
||||
cp = ""; /* no left-over text */
|
||||
}
|
||||
if (lookup == 0 || *lookup == 0 || (mc->flags & MAC_EXP_FLAG_SCAN))
|
||||
mc->status |= mac_parse(res_iffalse, mac_expand_callback,
|
||||
(char *) mc);
|
||||
if (*cp != 0) /* garbage */
|
||||
MAC_EXP_ERR_RETURN(mc, "unexpected input at: "
|
||||
"\"...%s}>>>%.20s\"", res_iffalse, cp);
|
||||
break;
|
||||
default:
|
||||
if (text == 0) {
|
||||
case 0:
|
||||
if (lookup == 0) {
|
||||
mc->status |= MAC_PARSE_UNDEF;
|
||||
} else if (*text == 0 || (mc->flags & MAC_EXP_FLAG_SCAN)) {
|
||||
} else if (*lookup == 0 || (mc->flags & MAC_EXP_FLAG_SCAN)) {
|
||||
/* void */ ;
|
||||
} else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
|
||||
vstring_strcpy(buf, text);
|
||||
mac_parse(vstring_str(buf), mac_expand_callback, (char *) mc);
|
||||
vstring_strcpy(buf, lookup);
|
||||
mc->status |= mac_parse(vstring_str(buf), mac_expand_callback,
|
||||
(char *) mc);
|
||||
} else {
|
||||
len = VSTRING_LEN(mc->result);
|
||||
vstring_strcat(mc->result, text);
|
||||
res_len = VSTRING_LEN(mc->result);
|
||||
vstring_strcat(mc->result, lookup);
|
||||
if (mc->flags & MAC_EXP_FLAG_PRINTABLE) {
|
||||
printable(vstring_str(mc->result) + len, '_');
|
||||
printable(vstring_str(mc->result) + res_len, '_');
|
||||
} else if (mc->filter) {
|
||||
cp = vstring_str(mc->result) + len;
|
||||
cp = vstring_str(mc->result) + res_len;
|
||||
while (*(cp += strspn(cp, mc->filter)))
|
||||
*cp++ = '_';
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg_panic("%s: unknown operator code %d", myname, ch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +525,7 @@ int mac_expand(VSTRING *result, const char *pattern, int flags,
|
||||
const char *filter,
|
||||
MAC_EXP_LOOKUP_FN lookup, char *context)
|
||||
{
|
||||
MAC_EXP mc;
|
||||
MAC_EXP_CONTEXT mc;
|
||||
int status;
|
||||
|
||||
/*
|
||||
|
@ -1,18 +1,60 @@
|
||||
name1 = name1-value
|
||||
name2 =
|
||||
|
||||
${name1?name 1 defined, |$name1|$name2|}
|
||||
${name1:name 1 undefined, |$name1|$name2|}
|
||||
${name2?name 2 defined, |$name1|$name2|}
|
||||
${name2:name 2 undefined, |$name1|$name2|}
|
||||
|$name1|$name2|
|
||||
$(name1
|
||||
$(name )
|
||||
${${name1} != {}?name 1 defined, |$name1|$name2|}
|
||||
${ ${name1} != {}?name 1 defined, |$name1|$name2|}
|
||||
${ ${name1} ?name 1 defined, |$name1|$name2|}
|
||||
${{$name1} ? {name 1 defined, |$name1|$name2|} : {name 1 undefined, |$name1|$name2|} }
|
||||
${x{$name1} != {}?{name 1 defined, |$name1|$name2|}}
|
||||
${{$name1}x?{name 1 defined, |$name1|$name2|}}
|
||||
${{$name1} != {}x{name 1 defined, |$name1|$name2|}}
|
||||
${{$name1} != {}?x{name 1 defined, |$name1|$name2|}}
|
||||
${{$name2} != {}?x{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}x}
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}x:{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}:x{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name2} != {}?{name 2 defined, |$name1|$name2|}:x{name 2 undefined, |$name1|$name2|}}
|
||||
${{text}}
|
||||
${{text}?{non-empty}:{empty}}
|
||||
${{text} = {}}
|
||||
${{${ name1}} == {}}
|
||||
${name1?{${ name1}}:{${name2}}}
|
||||
${name2?{${ name1}}:{${name2}}}
|
||||
${name2?{${name1}}:{${ name2}}}
|
||||
${name2:{${name1}}:{${name2}}}
|
||||
${name2?{${name1}}?{${name2}}}
|
||||
${{${name1?bug:test}} != {bug:test}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
${{${name1??bug}} != {?bug}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
${{${name2::bug}} != {:bug}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
${{xx}==(yy)?{oops}:{phew}}
|
||||
|
||||
name2 = name2-value
|
||||
name1 = name1-value
|
||||
|
||||
${name1?name 1 defined, |$name1|$name2|}
|
||||
${name1:name 1 undefined, |$name1|$name2|}
|
||||
${name2?name 2 defined, |$name1|$name2|}
|
||||
${name2:name 2 undefined, |$name1|$name2|}
|
||||
|$name1|$name2|
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}}
|
||||
${{$name1} != {}:{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} == {}?{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} == {}:{name 1 defined, |$name1|$name2|}}
|
||||
${name1?{name 1 defined, |$name1|$name2|}:{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}:{name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} != {} ? {name 1 defined, |$name1|$name2|} : {name 1 undefined, |$name1|$name2|}}
|
||||
${{$name1} != {}?{name 1 defined, |$name1|$name2|}:name 1 undefined, |$name1|$name2|}
|
||||
${{$name1} != {} ? {name 1 defined, |$name1|$name2|} : name 1 undefined, |$name1|$name2|}
|
||||
${{$name1} != {}}
|
||||
${{$name1} == {}}
|
||||
${{$name2} != {}?{name 2 defined, |$name1|$name2|}}
|
||||
${{$name2} != {}:{name 2 undefined, |$name1|$name2|}}
|
||||
${{$name2} == {}?{name 2 undefined, |$name1|$name2|}}
|
||||
${{$name2} == {}:{name 2 defined, |$name1|$name2|}}
|
||||
${name2?{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
${{$name2} != {}?{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
${{$name2} != {} ? {name 2 defined, |$name1|$name2|} : {name 2 undefined, |$name1|$name2|}}
|
||||
${{$name2} != {}?{name 2 defined, |$name1|$name2|}:name 2 undefined, |$name1|$name2|}
|
||||
${{$name2} != {} ? {name 2 defined, |$name1|$name2|} : name 2 undefined, |$name1|$name2|}
|
||||
${{$name2} != {}}
|
||||
${{$name2} == {}}
|
||||
|
@ -1,5 +1,84 @@
|
||||
<< name1 = name1-value
|
||||
<< name2 =
|
||||
<<
|
||||
<< $(name1
|
||||
unknown: warning: truncated macro reference: "$(name1"
|
||||
stat=1 result=
|
||||
<< $(name )
|
||||
unknown: warning: attribute name syntax error at: "...name>>> "
|
||||
stat=1 result=
|
||||
<< ${${name1} != {}?name 1 defined, |$name1|$name2|}
|
||||
unknown: warning: attribute name syntax error at: "...>>>${name1} != {}?name "
|
||||
stat=1 result=
|
||||
<< ${ ${name1} != {}?name 1 defined, |$name1|$name2|}
|
||||
unknown: warning: attribute name syntax error at: "...>>> ${name1} != {}?name"
|
||||
stat=1 result=
|
||||
<< ${ ${name1} ?name 1 defined, |$name1|$name2|}
|
||||
unknown: warning: attribute name syntax error at: "...>>> ${name1} ?name 1 de"
|
||||
stat=1 result=
|
||||
<< ${{$name1} ? {name 1 defined, |$name1|$name2|} : {name 1 undefined, |$name1|$name2|} }
|
||||
unknown: warning: "==" or "!=" expected at: "...$name1}>>>? {name 1 defined, |"
|
||||
stat=1 result=
|
||||
<< ${x{$name1} != {}?{name 1 defined, |$name1|$name2|}}
|
||||
unknown: warning: attribute name syntax error at: "...x>>>{$name1} != {}?{name"
|
||||
stat=1 result=
|
||||
<< ${{$name1}x?{name 1 defined, |$name1|$name2|}}
|
||||
unknown: warning: "==" or "!=" expected at: "...$name1}>>>x?{name 1 defined, |"
|
||||
stat=1 result=
|
||||
<< ${{$name1} != {}x{name 1 defined, |$name1|$name2|}}
|
||||
unknown: warning: "?" or ":" expected at: "...}>>>x{name 1 defined, |$"
|
||||
stat=1 result=
|
||||
<< ${{$name1} != {}?x{name 1 defined, |$name1|$name2|}}
|
||||
stat=2 result=x{name 1 defined, |name1-value||}
|
||||
<< ${{$name2} != {}?x{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}x}
|
||||
unknown: warning: ":" expected at: "...name 1 defined, |$name1|$name2|}>>>x"
|
||||
stat=3 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}x:{name 1 undefined, |$name1|$name2|}}
|
||||
unknown: warning: ":" expected at: "...name 1 defined, |$name1|$name2|}>>>x:{name 1 undefined,"
|
||||
stat=3 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}:x{name 1 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name2} != {}?{name 2 defined, |$name1|$name2|}:x{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=x{name 2 undefined, |name1-value||}
|
||||
<< ${{text}}
|
||||
unknown: warning: "==" or "!=" expected at: "...text}>>>"
|
||||
stat=1 result=
|
||||
<< ${{text}?{non-empty}:{empty}}
|
||||
unknown: warning: "==" or "!=" expected at: "...text}>>>?{non-empty}:{empty}"
|
||||
stat=1 result=
|
||||
<< ${{text} = {}}
|
||||
unknown: warning: "==" or "!=" expected at: "...text}>>>= {}"
|
||||
stat=1 result=
|
||||
<< ${{${ name1}} == {}}
|
||||
unknown: warning: attribute name syntax error at: "...>>> name1"
|
||||
stat=1 result=
|
||||
<< ${name1?{${ name1}}:{${name2}}}
|
||||
unknown: warning: attribute name syntax error at: "...>>> name1"
|
||||
stat=1 result=
|
||||
<< ${name2?{${ name1}}:{${name2}}}
|
||||
stat=2 result=
|
||||
<< ${name2?{${name1}}:{${ name2}}}
|
||||
unknown: warning: attribute name syntax error at: "...>>> name2"
|
||||
stat=1 result=
|
||||
<< ${name2:{${name1}}:{${name2}}}
|
||||
unknown: warning: unexpected input at: "...${name1}}>>>:{${name2}}"
|
||||
stat=1 result=name1-value
|
||||
<< ${name2?{${name1}}?{${name2}}}
|
||||
unknown: warning: ":" expected at: "...${name1}}>>>?{${name2}}"
|
||||
stat=1 result=
|
||||
<< ${{${name1?bug:test}} != {bug:test}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
stat=0 result=Good: Postfix 2.11 compatible
|
||||
<< ${{${name1??bug}} != {?bug}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
stat=0 result=Good: Postfix 2.11 compatible
|
||||
<< ${{${name2::bug}} != {:bug}?{Error: NOT}:{Good:}} Postfix 2.11 compatible
|
||||
stat=0 result=Good: Postfix 2.11 compatible
|
||||
<< ${{xx}==(yy)?{oops}:{phew}}
|
||||
unknown: warning: "{expression}" expected at: "...{xx} ??>>>(yy)?{oops}:{phew}"
|
||||
stat=1 result=
|
||||
<<
|
||||
|
||||
<< name1 = name1-value
|
||||
<<
|
||||
<< ${name1?name 1 defined, |$name1|$name2|}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
@ -11,23 +90,47 @@ stat=0 result=
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< |$name1|$name2|
|
||||
stat=2 result=|name1-value||
|
||||
<< $(name1
|
||||
unknown: warning: truncated macro reference: "$(name1"
|
||||
stat=1 result=
|
||||
<< $(name )
|
||||
unknown: warning: macro name syntax error: "name "
|
||||
stat=1 result=
|
||||
<<
|
||||
|
||||
<< name2 = name2-value
|
||||
<<
|
||||
<< ${name1?name 1 defined, |$name1|$name2|}
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}:{name 1 undefined, |$name1|$name2|}}
|
||||
stat=0 result=
|
||||
<< ${name1:name 1 undefined, |$name1|$name2|}
|
||||
stat=2 result=name 1 undefined, ||name2-value|
|
||||
<< ${name2?name 2 defined, |$name1|$name2|}
|
||||
stat=2 result=name 2 defined, ||name2-value|
|
||||
<< ${name2:name 2 undefined, |$name1|$name2|}
|
||||
<< ${{$name1} == {}?{name 1 undefined, |$name1|$name2|}}
|
||||
stat=0 result=
|
||||
<< |$name1|$name2|
|
||||
stat=2 result=||name2-value|
|
||||
<< ${{$name1} == {}:{name 1 defined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${name1?{name 1 defined, |$name1|$name2|}:{name 1 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}:{name 1 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {} ? {name 1 defined, |$name1|$name2|} : {name 1 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}?{name 1 defined, |$name1|$name2|}:name 1 undefined, |$name1|$name2|}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {} ? {name 1 defined, |$name1|$name2|} : name 1 undefined, |$name1|$name2|}
|
||||
stat=2 result=name 1 defined, |name1-value||
|
||||
<< ${{$name1} != {}}
|
||||
stat=0 result=true
|
||||
<< ${{$name1} == {}}
|
||||
stat=0 result=
|
||||
<< ${{$name2} != {}?{name 2 defined, |$name1|$name2|}}
|
||||
stat=2 result=
|
||||
<< ${{$name2} != {}:{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} == {}?{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} == {}:{name 2 defined, |$name1|$name2|}}
|
||||
stat=2 result=
|
||||
<< ${name2?{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} != {}?{name 2 defined, |$name1|$name2|}:{name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} != {} ? {name 2 defined, |$name1|$name2|} : {name 2 undefined, |$name1|$name2|}}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} != {}?{name 2 defined, |$name1|$name2|}:name 2 undefined, |$name1|$name2|}
|
||||
stat=2 result=name 2 undefined, |name1-value||
|
||||
<< ${{$name2} != {} ? {name 2 defined, |$name1|$name2|} : name 2 undefined, |$name1|$name2|}
|
||||
stat=2 result= name 2 undefined, |name1-value||
|
||||
<< ${{$name2} != {}}
|
||||
stat=2 result=
|
||||
<< ${{$name2} == {}}
|
||||
stat=2 result=true
|
||||
|
@ -114,7 +114,7 @@ static ARGV *match_list_parse(ARGV *list, char *string, int init_match)
|
||||
* /filename contents are expanded in-line. To support !/filename we
|
||||
* prepend the negation operator to each item from the file.
|
||||
*/
|
||||
while ((start = mystrtok(&bp, delim)) != 0) {
|
||||
while ((start = mystrtokq(&bp, delim, "{}")) != 0) {
|
||||
if (*start == '#') {
|
||||
msg_warn("%s: comment at end of line is not supported: %s %s",
|
||||
myname, start, bp);
|
||||
|
@ -43,7 +43,7 @@ extern void msg_error_clear(void);
|
||||
extern MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN);
|
||||
|
||||
extern void PRINTFLIKE(4, 5) msg_rate_delay(time_t *, int,
|
||||
void (*log_fn) (const char *,...),
|
||||
void PRINTFLIKE(1, 2) (*log_fn) (const char *,...),
|
||||
const char *,...);
|
||||
|
||||
/* LICENSE
|
||||
|
@ -9,11 +9,21 @@
|
||||
/* char *mystrtok(bufp, delimiters)
|
||||
/* char **bufp;
|
||||
/* const char *delimiters;
|
||||
/*
|
||||
/* char *mystrtokq(bufp, delimiters, parens)
|
||||
/* char **bufp;
|
||||
/* const char *delimiters;
|
||||
/* const char *parens;
|
||||
/* DESCRIPTION
|
||||
/* mystrtok() splits a buffer on the specified \fIdelimiters\fR.
|
||||
/* Tokens are delimited by runs of delimiters, so this routine
|
||||
/* cannot return zero-length tokens.
|
||||
/*
|
||||
/* mystrtokq() is like mystrtok() but will not split text
|
||||
/* between balanced parentheses. \fIparens\fR specifies the
|
||||
/* opening and closing parenthesis (one of each). The set of
|
||||
/* \fIparens\fR must be distinct from the set of \fIdelimiters\fR.
|
||||
/*
|
||||
/* The \fIbufp\fR argument specifies the start of the search; it
|
||||
/* is updated with each call. The input is destroyed.
|
||||
/*
|
||||
@ -65,6 +75,41 @@ char *mystrtok(char **src, const char *sep)
|
||||
return (start);
|
||||
}
|
||||
|
||||
/* mystrtokq - safe tokenizer with quoting support */
|
||||
|
||||
char *mystrtokq(char **src, const char *sep, const char *parens)
|
||||
{
|
||||
char *start = *src;
|
||||
static char *cp;
|
||||
int ch;
|
||||
int level;
|
||||
|
||||
/*
|
||||
* Skip over leading delimiters.
|
||||
*/
|
||||
start += strspn(start, sep);
|
||||
if (*start == 0) {
|
||||
*src = start;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse out the next token.
|
||||
*/
|
||||
for (level = 0, cp = start; (ch = *(unsigned char *) cp) != 0; cp++) {
|
||||
if (ch == parens[0]) {
|
||||
level++;
|
||||
} else if (level > 0 && ch == parens[1]) {
|
||||
level--;
|
||||
} else if (level == 0 && strchr(sep, ch) != 0) {
|
||||
*cp++ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*src = cp;
|
||||
return (start);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
@ -80,10 +125,15 @@ int main(void)
|
||||
char *start;
|
||||
char *str;
|
||||
|
||||
while (vstring_fgets(vp, VSTREAM_IN)) {
|
||||
while (vstring_fgets(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) {
|
||||
start = vstring_str(vp);
|
||||
while ((str = mystrtok(&start, " \t\r\n")) != 0)
|
||||
vstream_printf(">%s<\n", str);
|
||||
if (strchr(start, '{') == 0) {
|
||||
while ((str = mystrtok(&start, " \t\r\n")) != 0)
|
||||
vstream_printf(">%s<\n", str);
|
||||
} else {
|
||||
while ((str = mystrtokq(&start, " \t\r\n", "{}")) != 0)
|
||||
vstream_printf(">%s<\n", str);
|
||||
}
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
vstring_free(vp);
|
||||
|
@ -28,6 +28,7 @@ extern char *skipblanks(const char *);
|
||||
extern char *trimblanks(char *, int);
|
||||
extern char *concatenate(const char *,...);
|
||||
extern char *mystrtok(char **, const char *);
|
||||
extern char *mystrtokq(char **, const char *, const char *);
|
||||
extern char *translit(char *, const char *, const char *);
|
||||
#ifndef HAVE_BASENAME
|
||||
#define basename postfix_basename
|
||||
@ -43,6 +44,7 @@ extern int allspace(const char *);
|
||||
extern int allascii(const char *);
|
||||
extern const char *split_nameval(char *, char **, char **);
|
||||
extern int valid_utf8_string(const char *, ssize_t);
|
||||
extern size_t balpar(const char *, const char *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@ -151,7 +151,7 @@ VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
|
||||
* strings, since we are ging to let sprintf() do the hard work.
|
||||
* In regular expression notation, we recognize:
|
||||
*
|
||||
* %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-zA-Z]
|
||||
* %-?0?([0-9]+|\*)?\.(?[0-9]+|\*)?l?[a-zA-Z]
|
||||
*
|
||||
* which includes some combinations that do not make sense. Garbage
|
||||
* in, garbage out.
|
||||
@ -178,21 +178,24 @@ VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
|
||||
msg_warn("%s: bad width %d in %.50s", myname, width, format);
|
||||
width = 0;
|
||||
}
|
||||
if (*cp == '.') /* width/precision separator */
|
||||
if (*cp == '.') { /* width/precision separator */
|
||||
VSTRING_ADDCH(fmt, *cp++);
|
||||
if (*cp == '*') { /* dynamic precision */
|
||||
prec = va_arg(ap, int);
|
||||
VSTRING_ADDNUM(fmt, prec);
|
||||
cp++;
|
||||
} else { /* hard-coded precision */
|
||||
for (prec = 0; ch = *cp, ISDIGIT(ch); cp++) {
|
||||
prec = prec * 10 + ch - '0';
|
||||
VSTRING_ADDCH(fmt, ch);
|
||||
if (*cp == '*') { /* dynamic precision */
|
||||
prec = va_arg(ap, int);
|
||||
VSTRING_ADDNUM(fmt, prec);
|
||||
cp++;
|
||||
} else { /* hard-coded precision */
|
||||
for (prec = 0; ch = *cp, ISDIGIT(ch); cp++) {
|
||||
prec = prec * 10 + ch - '0';
|
||||
VSTRING_ADDCH(fmt, ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prec < 0) {
|
||||
msg_warn("%s: bad precision %d in %.50s", myname, prec, format);
|
||||
prec = 0;
|
||||
if (prec < 0) {
|
||||
msg_warn("%s: bad precision %d in %.50s", myname, prec, format);
|
||||
prec = -1;
|
||||
}
|
||||
} else {
|
||||
prec = -1;
|
||||
}
|
||||
if ((long_flag = (*cp == 'l')) != 0)/* long whatever */
|
||||
VSTRING_ADDCH(fmt, *cp++);
|
||||
@ -210,7 +213,7 @@ VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
|
||||
switch (*cp) {
|
||||
case 's': /* string-valued argument */
|
||||
s = va_arg(ap, char *);
|
||||
if (prec > 0 || (width > 0 && width > strlen(s))) {
|
||||
if (prec >= 0 || (width > 0 && width > strlen(s))) {
|
||||
if (VBUF_SPACE(bp, (width > prec ? width : prec) + INT_SPACE))
|
||||
return (bp);
|
||||
sprintf((char *) bp->ptr, vstring_str(fmt), s);
|
||||
|
Loading…
x
Reference in New Issue
Block a user