Cleanup: replace stress-dependent main.cf defaults with the
ternary form: "${stress?{x}:{y}}" File: global/mail_params.h,
proto/postconf.proto, postscreen/postscreen.c (comments).
+
+20140923
+
+ Cleanup: dict_db and dict_lmdb global settings. Files:
+ global/mail_params.c, util/dict_open.c.
+
+ Feature: unionmap, based on contribution by Roel van Meer.
+ Files: mantools/postlink, postconf/postconf.c (manpage),
+ proto/DATABASE_README.html, util/dict_open.c, util/dict_union.[hc].
and that texthash: does not detect changes after the file is read. The
lookup table name is "texthash:filename", where the file name is taken
literally; no suffix is appended.
+ u\bun\bni\bio\bon\bnm\bma\bap\bp (read-only)
+ A table that sends each query to multiple lookup tables and that
+ concatenates all found results, separated by comma. The table name
+ syntax is the same as for pipemap tables.
u\bun\bni\bix\bx (read-only)
A limited view of the UNIX authentication database. The following
tables are implemented:
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
file is read. The lookup table name is "<a href="DATABASE_README.html#types">texthash</a>:filename", where
the file name is taken literally; no suffix is appended. </dd>
+<dt> <b>unionmap</b> (read-only) </dt>
+
+<dd> A table that sends each query to multiple lookup tables and
+that concatenates all found results, separated by comma. The table
+name syntax is the same as for pipemap tables. </dd>
+
<dt> <b>unix</b> (read-only) </dt>
<dd> A limited view of the UNIX authentication database. The following
use the file, and that it does not detect changes after
the file is read.
+ <b>union</b> (read-only)
+ A table that sends each query to multiple lookup tables
+ and that concatenates all found results, separated by
+ comma. The table name syntax is the same as for <b>pipemap</b>.
+
<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>,
+ <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>
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‐
+ <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
+ <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
+ <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‐
mand line.
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‐
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>
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
don't need to run the \fBpostmap\fR(1) command before you
can use the file, and that it does not detect changes after
the file is read.
+.IP "\fBunion\fR (read-only)"
+A table that sends each query to multiple lookup tables and
+that concatenates all found results, separated by comma.
+The table name syntax is the same as for \fBpipemap\fR.
.IP "\fBunix\fR (read-only)"
A limited view of the UNIX authentication database. The
following tables are implemented:
s/\b(tcp):/<a href="tcp_table.5.html">$1<\/a>:/g;
s/\b(texthash):/<a href="DATABASE_README.html#types">$1<\/a>:/g;
#s/\b(unix):/<a href="DATABASE_README.html#types">$1<\/a>:/g;
+ s/\b(unionmap):/<a href="DATABASE_README.html#types">$1<\/a>:/g;
# Do nice links for smtp:host:port etc.
file is read. The lookup table name is "texthash:filename", where
the file name is taken literally; no suffix is appended. </dd>
+<dt> <b>unionmap</b> (read-only) </dt>
+
+<dd> A table that sends each query to multiple lookup tables and
+that concatenates all found results, separated by comma. The table
+name syntax is the same as for pipemap tables. </dd>
+
<dt> <b>unix</b> (read-only) </dt>
<dd> A limited view of the UNIX authentication database. The following
const char null_format_string[1] = "";
-DEFINE_DICT_LMDB_MAP_SIZE;
-DEFINE_DICT_DB_CACHE_SIZE;
-
/* check_myhostname - lookup hostname and validate */
static const char *check_myhostname(void)
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20140922"
+#define MAIL_RELEASE_DATE "20140923"
#define MAIL_VERSION_NUMBER "2.12"
#ifdef SNAPSHOT
rm -f $@
(echo "# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE"; \
echo "# TEXT HERE JUST SHOWS DEFAULT SETTINGS BUILT INTO POSTFIX."; \
- echo "#"; $(SHLIB_ENV) ./$(PROG) -d -c ../../conf) | \
+ echo "#"; $(SHLIB_ENV) $(SHLIB_ENV) ./$(PROG) -d -c ../../conf) | \
egrep -v '^(myhostname|mydomain|mynetworks|process_name|process_id) ' >$@
$(OBJS): ../../conf/makedefs.out
echo smtpd_restriction_classes = foo bar >> main.cf
echo foo = yes >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test1.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test1.tmp 2>&1
diff test1.ref test1.tmp
rm -f main.cf master.cf test1.tmp
echo restriction_classes = foo bar >> main.cf
echo foo = yes >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test2.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test2.tmp 2>&1
diff test2.ref test2.tmp
rm -f main.cf master.cf test2.tmp
echo 'bar = $$foo' >> main.cf
echo 'always_bcc = $$bar' >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test3.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test3.tmp 2>&1
diff test3.ref test3.tmp
rm -f main.cf master.cf test3.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test4.tmp 2>&1
diff test4.ref test4.tmp
rm -f main.cf master.cf test4.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test4b.tmp 2>&1
diff test4b.ref test4b.tmp
rm -f main.cf master.cf test4b.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test5.tmp 2>&1
diff test5.ref test5.tmp
rm -f main.cf master.cf test5.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . 2>&1 | grep whatevershebrings >test6.tmp
diff test6.ref test6.tmp
rm -f main.cf master.cf test6.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . 2>&1 | grep whatevershebrings >test7.tmp
diff test7.ref test7.tmp
rm -f main.cf master.cf test7.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . 2>&1 | grep whatevershebrings >test8.tmp
diff test8.ref test8.tmp
rm -f main.cf master.cf test8.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -M '*'/inet >test9.tmp 2>&1
diff test9.ref test9.tmp
rm -f main.cf master.cf test9.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -M bar/inet foo/unix >test10.tmp 2>&1
diff test10.ref test10.tmp
rm -f main.cf master.cf test10.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -M >test11.tmp 2>&1
diff test11.ref test11.tmp
rm -f main.cf master.cf test11.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -M >test12.tmp 2>&1
diff test12.ref test12.tmp
rm -f main.cf master.cf test12.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test13.tmp 2>&1
diff test13.ref test13.tmp
rm -f main.cf master.cf test13.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test14.tmp 2>&1
diff test14.ref test14.tmp
rm -f main.cf master.cf test14.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test15.tmp 2>&1
diff test15.ref test15.tmp
rm -f main.cf master.cf test15.tmp
test16: $(PROG) test16.ref
rm -f main.cf master.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test16.tmp 2>&1
+ $(SHLIB_ENV) ./$(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 -t 197101010000 main.cf
- -./$(PROG) -Mc . >test17.tmp 2>&1; exit 0
+ -$(SHLIB_ENV) ./$(PROG) -Mc . >test17.tmp 2>&1; exit 0
diff test17.ref test17.tmp
rm -f main.cf master.cf test17.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . >test18.tmp 2>&1
diff test18.ref test18.tmp
rm -f main.cf master.cf test18.tmp
echo forward_path='$$'aaaa >> main.cf
echo default_rbl_reply='$$'bbbb >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test19.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test19.tmp 2>&1
diff test19.ref test19.tmp
rm -f main.cf master.cf test19.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc . >test20.tmp 2>&1
diff test20.ref test20.tmp
rm -f main.cf master.cf test20.tmp
echo forward_path = xxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxx \
xxxxxxxxxxxxx xxxxxxxxxxxxxx >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nfc . >test21.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nfc . >test21.tmp 2>&1
diff test21.ref test21.tmp
rm -f main.cf master.cf test21.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . 2>&1 | grep whatevershebrings >test22.tmp
diff test22.ref test22.tmp
rm -f main.cf master.cf test22.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -nC builtin >test23.tmp 2>&1
diff test23.ref test23.tmp
rm -f main.cf master.cf test23.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -nC user >test24.tmp 2>&1
diff test24.ref test24.tmp
rm -f main.cf master.cf test24.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -C service 2>&1 | grep whatevershebrings >test25.tmp
diff test25.ref test25.tmp
rm -f main.cf master.cf test25.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nc . -C all >test26.tmp 2>&1
diff test26.ref test26.tmp
rm -f main.cf master.cf test26.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -c . -C all 2>&1 | grep whatevershebrings >test27.tmp
diff test27.ref test27.tmp
rm -f main.cf master.cf test27.tmp
echo 'zz_domain = whatever' >> main.cf
echo 'aa_domain = whatever' >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test28.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test28.tmp 2>&1
diff test28.ref test28.tmp
rm -f main.cf master.cf test28.tmp
echo 'memcachefoo_domain = bar' >> main.cf
echo 'memcachefoo_domainx = bar' >> main.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test29.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test29.tmp 2>&1
diff test29.ref test29.tmp
rm -f main.cf master.cf test29.tmp
echo ' -oheader_checks=$$p3' >> master.cf
echo ' -oheaderx_checks=$$p4' >> master.cf
touch -t 197101010000 main.cf
- ./$(PROG) -nc . >test30.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -nc . >test30.tmp 2>&1
diff test30.ref test30.tmp
rm -f main.cf master.cf test30.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nxc . >test31.tmp 2>&1
diff test31.ref test31.tmp
rm -f main.cf master.cf test31.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -xc . fast_flush_domains >test32.tmp 2>&1
diff test32.ref test32.tmp
rm -f main.cf master.cf test32.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -xc . always_bcc >test33.tmp 2>&1
diff test33.ref test33.tmp
rm -f main.cf master.cf test33.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -xc . mydestination process_name >test34.tmp 2>&1
diff test34.ref test34.tmp
rm -f main.cf master.cf test34.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -xc . process_name >test35.tmp 2>&1
diff test35.ref test35.tmp
rm -f main.cf master.cf test35.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nxc . >test36.tmp 2>&1
diff test36.ref test36.tmp
rm -f main.cf master.cf test36.tmp
echo ' -o always_bcc=$$aaa' >> master.cf
echo ' -o aaa=ccc' >> master.cf
touch -t 197101010000 main.cf
- ./$(PROG) -Mfxc . >test37.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfxc . >test37.tmp 2>&1
diff test37.ref test37.tmp
rm -f main.cf master.cf test37.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc . '*'/unix >test39.tmp 2>&1
diff test39.ref test39.tmp
rm -f main.cf master.cf test39.tmp
echo ' -vo ccc=$$aaa' >> master.cf
echo ' -v -oddd=$$ccc' >> master.cf
touch -t 197101010000 main.cf
- ./$(PROG) -Mfxc . '*'/unix >test40.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfxc . '*'/unix >test40.tmp 2>&1
diff test40.ref test40.tmp
rm -f main.cf master.cf test40.tmp
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
- ./$(PROG) -Mfc. >>test41.tmp 2>&1
- ./$(PROG) -Pc . >>test41.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test41.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test41.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Pc . bar/unix/xxx=YYY bar/unix/aaa=BBB >>test41.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test41.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Pc . >>test41.tmp 2>&1
diff test41.ref test41.tmp
rm -f main.cf master.cf test41.tmp
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
- ./$(PROG) -PXc. bar/unix/xxx bar/unix/aaa >>test42.tmp 2>&1
- ./$(PROG) -Mfc. >>test42.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test42.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test42.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Pc . >>test42.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -PXc. bar/unix/xxx bar/unix/aaa >>test42.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test42.tmp 2>&1
diff test42.ref test42.tmp
rm -f main.cf master.cf test42.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Fc . bar/unix/chroot=y bar/unix/command='aa -stuffobb=cc dd' >test43.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test43.tmp 2>&1
diff test43.ref test43.tmp
rm -f main.cf master.cf test43.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mc . bar/unix='xx inet - n n - 0 aa -stuffobb=cc dd' >test44.tmp 2>&1
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >>test44.tmp 2>&1
diff test44.ref test44.tmp
rm -f main.cf master.cf test44.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test45.tmp 2>&1 || true
diff test45.ref test45.tmp
rm -f main.cf master.cf test45.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test46.tmp 2>&1 || true
diff test46.ref test46.tmp
rm -f main.cf master.cf test46.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test47.tmp 2>&1 || true
diff test47.ref test47.tmp
rm -f main.cf master.cf test47.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test48.tmp 2>&1 || true
diff test48.ref test48.tmp
rm -f main.cf master.cf test48.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test49.tmp 2>&1 || true
diff test49.ref test49.tmp
rm -f main.cf master.cf test49.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test50.tmp 2>&1 || true
diff test50.ref test50.tmp
rm -f main.cf master.cf test50.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test51.tmp 2>&1 || true
diff test51.ref test51.tmp
rm -f main.cf master.cf test51.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -MXc. bar/inet foo/unix xxx/yyy
+ $(SHLIB_ENV) ./$(PROG) -Mfc. >test52.tmp 2>&1 || true
diff test52.ref test52.tmp
rm -f main.cf master.cf test52.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -M#c. bar/inet xxx/yyy
diff test53.ref master.cf
rm -f main.cf master.cf test53.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -M#c. bar/inet foo/unix
diff test54.ref master.cf
rm -f main.cf master.cf test54.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -M#c. bar/inet baz/unix
diff test55.ref master.cf
rm -f main.cf master.cf test55.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -M#c. bar/inet xxx/yyy
diff test56.ref master.cf
rm -f main.cf master.cf test56.tmp
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
+ $(SHLIB_ENV) ./$(PROG) -nxc. >test57.tmp 2>&1
diff test57.ref test57.tmp
rm -f main.cf master.cf test57.tmp
/* don't need to run the \fBpostmap\fR(1) command before you
/* can use the file, and that it does not detect changes after
/* the file is read.
+/* .IP "\fBunion\fR (read-only)"
+/* A table that sends each query to multiple lookup tables and
+/* that concatenates all found results, separated by comma.
+/* The table name syntax is the same as for \fBpipemap\fR.
/* .IP "\fBunix\fR (read-only)"
/* A limited view of the UNIX authentication database. The
/* following tables are implemented:
+./postconf: warning: main.cf: syntax error after '}' in "pipemap:{ldap:xxx, memcache:yy}x"
./postconf: warning: main.cf: missing '}' in parameter value: "randmap:{xx"
config_directory = .
-mydestination = foo bar pipemap:{ldap:xxx, memcache:yy} randmap:{xx
+mydestination = foo bar pipemap:{ldap:xxx, memcache:yy}x randmap:{xx
xxx_domain = foo
yy_backup = bbb
./postconf: warning: ./main.cf: unused parameter: yy_bogus=bbb
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 argv_splitq.c balpar.c
+ valid_utf8_hostname.c midna.c argv_splitq.c balpar.c dict_union.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 \
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 argv_splitq.o balpar.o
+ valid_utf8_hostname.o midna.o argv_splitq.o balpar.o dict_union.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.
edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \
dict_fail.h warn_stat.h dict_sockmap.h line_number.h timecmp.h \
slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
- valid_utf8_hostname.h midna.h
+ valid_utf8_hostname.h midna.h dict_union.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
DEFS = -I. -D$(SYSTYPE)
dict_open.o: dict_static.h
dict_open.o: dict_tcp.h
dict_open.o: dict_thash.h
+dict_open.o: dict_union.h
dict_open.o: dict_unix.h
dict_open.o: htable.h
dict_open.o: msg.h
dict_thash.o: vstream.h
dict_thash.o: vstring.h
dict_thash.o: warn_stat.h
+dict_union.o: argv.h
+dict_union.o: dict.h
+dict_union.o: dict_union.c
+dict_union.o: dict_union.h
+dict_union.o: htable.h
+dict_union.o: msg.h
+dict_union.o: myflock.h
+dict_union.o: mymalloc.h
+dict_union.o: stringops.h
+dict_union.o: sys_defs.h
+dict_union.o: vbuf.h
+dict_union.o: vstream.h
+dict_union.o: vstring.h
dict_unix.o: argv.h
dict_unix.o: dict.h
dict_unix.o: dict_unix.c
load_file.o: vstream.h
load_file.o: warn_stat.h
load_lib.o: load_lib.c
+load_lib.o: load_lib.h
+load_lib.o: msg.h
load_lib.o: sys_defs.h
lowercase.o: lowercase.c
lowercase.o: stringops.h
mac_expand.o: mac_parse.h
mac_expand.o: msg.h
mac_expand.o: mymalloc.h
+mac_expand.o: name_code.h
mac_expand.o: stringops.h
mac_expand.o: sys_defs.h
mac_expand.o: vbuf.h
#include <dict_fail.h>
#include <dict_pipe.h>
#include <dict_random.h>
+#include <dict_union.h>
#include <stringops.h>
#include <split_at.h>
#include <htable.h>
DICT_TYPE_FAIL, dict_fail_open,
DICT_TYPE_PIPE, dict_pipe_open,
DICT_TYPE_RANDOM, dict_random_open,
+ DICT_TYPE_UNION, dict_union_open,
#ifndef USE_DYNAMIC_MAPS
#ifdef HAS_PCRE
DICT_TYPE_PCRE, dict_pcre_open,
static DICT_OPEN_EXTEND_FN dict_open_extend_hook;
static DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend_hook;
+ /*
+ * Workaround.
+ */
+DEFINE_DICT_LMDB_MAP_SIZE;
+DEFINE_DICT_DB_CACHE_SIZE;
+
/* dict_open_init - one-off initialization */
static void dict_open_init(void)
#ifdef TEST
-DEFINE_DICT_LMDB_MAP_SIZE;
-DEFINE_DICT_DB_CACHE_SIZE;
-
/*
* Proof-of-concept test program.
*/
--- /dev/null
+/*++
+/* NAME
+/* dict_union 3
+/* SUMMARY
+/* dictionary manager interface for union of tables
+/* SYNOPSIS
+/* #include <dict_union.h>
+/*
+/* DICT *dict_union_open(name, open_flags, dict_flags)
+/* const char *name;
+/* int open_flags;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_union_open() opens a sequence of one or more tables.
+/* Example: "\fBunionmap:{\fItype_1:name_1, ..., type_n:name_n\fR}".
+/*
+/* Each "unionmap:" query is given to each table in the specified
+/* order. All found results are concatenated, separated by
+/* comma. The unionmap table produces no result when all
+/* lookup tables return no result.
+/*
+/* The first and last characters of a "unionmap:" 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.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <dict.h>
+#include <dict_union.h>
+#include <stringops.h>
+#include <vstring.h>
+
+/* Application-specific. */
+
+typedef struct {
+ DICT dict; /* generic members */
+ ARGV *map_union; /* pipelined tables */
+ VSTRING *re_buf; /* reply buffer */
+} DICT_UNION;
+
+#define STR(x) vstring_str(x)
+
+/* dict_union_lookup - search a bunch of tables and combine the results */
+
+static const char *dict_union_lookup(DICT *dict, const char *query)
+{
+ const char myname[] = "dict_union_lookup";
+ DICT_UNION *dict_union = (DICT_UNION *) dict;
+ DICT *map;
+ char **cpp;
+ char *dict_type_name;
+ const char *result = 0;
+
+ /*
+ * After Roel van Meer, postfix-users mailing list, Sept 2014.
+ */
+ VSTRING_RESET(dict_union->re_buf);
+ for (cpp = dict_union->map_union->argv; (dict_type_name = *cpp) != 0; cpp++) {
+ if ((map = dict_handle(dict_type_name)) == 0)
+ msg_panic("%s: dictionary \"%s\" not found", myname, dict_type_name);
+ if ((result = dict_get(map, query)) == 0)
+ continue;
+ if (VSTRING_LEN(dict_union->re_buf) > 0)
+ VSTRING_ADDCH(dict_union->re_buf, ',');
+ vstring_strcat(dict_union->re_buf, result);
+ }
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE,
+ VSTRING_LEN(dict_union->re_buf) > 0 ?
+ STR(dict_union->re_buf) : 0);
+}
+
+/* dict_union_close - disassociate from a bunch of tables */
+
+static void dict_union_close(DICT *dict)
+{
+ DICT_UNION *dict_union = (DICT_UNION *) dict;
+ char **cpp;
+ char *dict_type_name;
+
+ for (cpp = dict_union->map_union->argv; (dict_type_name = *cpp) != 0; cpp++)
+ dict_unregister(dict_type_name);
+ argv_free(dict_union->map_union);
+ vstring_free(dict_union->re_buf);
+ dict_free(dict);
+}
+
+/* dict_union_open - open a bunch of tables */
+
+DICT *dict_union_open(const char *name, int open_flags, int dict_flags)
+{
+ const char myname[] = "dict_union_open";
+ DICT_UNION *dict_union;
+ char *saved_name = 0;
+ char *dict_type_name;
+ ARGV *argv = 0;
+ char **cpp;
+ DICT *dict;
+ int match_flags = 0;
+ struct DICT_OWNER aggr_owner;
+ size_t len;
+
+ /*
+ * Clarity first. Let the optimizer worry about redundant code.
+ */
+#define DICT_UNION_RETURN(x) do { \
+ if (saved_name != 0) \
+ myfree(saved_name); \
+ if (argv != 0) \
+ argv_free(argv); \
+ return (x); \
+ } while (0)
+
+ /*
+ * Sanity checks.
+ */
+ if (open_flags != O_RDONLY)
+ DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name,
+ open_flags, dict_flags,
+ "%s:%s map requires O_RDONLY access mode",
+ DICT_TYPE_UNION, name));
+
+ /*
+ * Split the table name into its constituent parts.
+ */
+ saved_name = mystrdup(name + 1); /* XXX ASCII delimiter */
+ if ((len = balpar(name, "{}")) == 0 || name[len] != 0
+ || *(saved_name = mystrndup(name + 1, len - 2)) == 0)
+ DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name,
+ open_flags, dict_flags,
+ "bad syntax: \"%s:%s\"; "
+ "need \"%s:{type:name...}\"",
+ DICT_TYPE_UNION, name,
+ DICT_TYPE_UNION));
+
+ /*
+ * The least-trusted table in the set determines the over-all trust
+ * level. The first table determines the pattern-matching flags.
+ */
+ DICT_OWNER_AGGREGATE_INIT(aggr_owner);
+ 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);
+ if (strchr(dict_type_name, ':') == 0)
+ DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name,
+ open_flags, dict_flags,
+ "bad syntax: \"%s:%s\"; "
+ "need \"%s:{type:name...}\"",
+ DICT_TYPE_UNION, name,
+ DICT_TYPE_UNION));
+ if ((dict = dict_handle(dict_type_name)) == 0)
+ dict = dict_open(dict_type_name, open_flags, dict_flags);
+ dict_register(dict_type_name, dict);
+ DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner);
+ if (cpp == argv->argv)
+ match_flags = dict->flags & (DICT_FLAG_FIXED | DICT_FLAG_PATTERN);
+ }
+
+ /*
+ * Bundle up the result.
+ */
+ dict_union =
+ (DICT_UNION *) dict_alloc(DICT_TYPE_UNION, name, sizeof(*dict_union));
+ dict_union->dict.lookup = dict_union_lookup;
+ dict_union->dict.close = dict_union_close;
+ dict_union->dict.flags = dict_flags | match_flags;
+ dict_union->dict.owner = aggr_owner;
+ dict_union->re_buf = vstring_alloc(100);
+ dict_union->map_union = argv;
+ argv = 0;
+ DICT_UNION_RETURN(DICT_DEBUG (&dict_union->dict));
+}
--- /dev/null
+#ifndef _DICT_UNION_H_INCLUDED_
+#define _DICT_UNION_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_union 3h
+/* SUMMARY
+/* dictionary manager interface for union of tables
+/* SYNOPSIS
+/* #include <dict_union.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_UNION "unionmap"
+
+extern DICT *dict_union_open(const char *, int, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif