-TBOUNCE_TIME_PARAMETER
-TCFG_PARSER
-TCIDR_MATCH
--TCLEANUP_BODY_REGION
+-TCLEANUP_REGION
-TCLEANUP_STATE
-TCLEANUP_STAT_DETAIL
-TCLIENT_LIST
as it was before the body was replaced. Files: milter/milter8.c,
cleanup/cleanup_milter.c, cleanup/cleanup_body_region.c.
+20070117
+
+ Cleanup: reusable infrastructure for body replacement.
+ Files: cleanup/cleanup_body_edit.c, cleanup/cleanup_region.c.
+
+20070118
+
+ Bugfix: match lists didn't implement !maptype:mapname.
+ Problem reported by Paulo Pacheco. File: util/match_list.c.
+
+ Cleanup: revised the matchlist "!" support, added support
+ for !/file/name, and updated the documentation. File:
+ util/match_list.c.
+
Wish list:
+ Need scache size limit.
+
+ Don't transform bare username into user@localdomain.localdomain
+ when no domain is specified via main.cf or via the machine
+ hostname.
+
Update BACKSCATTER_README to use PCRE because that's what I
am using now.
$readme_directory/SMTPD_POLICY_README:f:root:-:644
$readme_directory/SMTPD_PROXY_README:f:root:-:644
$readme_directory/STANDARD_CONFIGURATION_README:f:root:-:644
+$readme_directory/TLS_LEGACY_README:f:root:-:644
$readme_directory/TLS_README:f:root:-:644
$readme_directory/TUNING_README:f:root:-:644
$readme_directory/ULTRIX_README:f:root:-:644
<p>
Specify a list of user names, "/file/name" or "<a href="DATABASE_README.html">type:table</a>" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
This feature is available in Postfix 2.2 and later.
<p>
Specify a list of user names, "/file/name" or "<a href="DATABASE_README.html">type:table</a>" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a user name from the list. The form "!/file/name" is
+supported only in Postfix version 2.4 and later. </p>
<p>
This feature is available in Postfix 2.2 and later.
<p>
Specify a list of user names, "/file/name" or "<a href="DATABASE_README.html">type:table</a>" patterns,
separated by commas and/or whitespace. The list is matched left to right,
-and the search stops on the first match. Specify "!name" to exclude a
-name from the list. A "/file/name" pattern is replaced by its contents;
+and the search stops on the first match. A "/file/name" pattern is
+replaced by its contents;
a "<a href="DATABASE_README.html">type:table</a>" lookup table is matched when a name matches a lookup key
(the lookup result is ignored). Continue long lines by starting the
-next line with whitespace. </p>
+next line with whitespace. Specify "!pattern" to exclude a user
+name from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p>
Example:
pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a> value, and in files
<p>
Specify a list of user names, "/file/name" or "<a href="DATABASE_README.html">type:table</a>" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
Examples:
<p> The list is matched left to right, and the search stops on the
first match. Specify "!pattern" to exclude an address or network
-block from the list. </p>
+block from the list. The form "!/file/name" is supported only
+in Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#mynetworks">mynetworks</a> value, and in files specified with
<p>
Patterns are separated by whitespace and/or commas. In order to
-reverse the result, precede a non-file name pattern with an
-exclamation point (!).
+reverse the result, precede a pattern with an
+exclamation point (!). The form "!/file/name" is supported only
+in Postfix version 2.4 and later.
</p>
<p>
Continue long lines by starting the next line with whitespace. A
"/file/name" pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>"
lookup table is matched when a (parent) domain appears as lookup
-key. </p>
+key. Specify "!pattern" to exclude a domain from the list. The form
+"!/file/name" is supported only in Postfix version 2.4 and later.
+</p>
</DD>
<p> Specify mechanism names, "/file/name" patterns or "<a href="DATABASE_README.html">type:table</a>"
lookup tables. The right-hand side result from "<a href="DATABASE_README.html">type:table</a>" lookups
-is ignored. </p>
+is ignored. Specify "!pattern" to exclude a mechanism name from the
+list. The form "!/file/name" is supported only in Postfix version
+2.4 and later. </p>
<p> This feature is available in Postfix 2.2 and later. </p>
pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_verp_clients">smtpd_authorized_verp_clients</a> value, and in
pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a> value, and in
pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a> value, and in
"<a href="DATABASE_README.html">type:table</a>" patterns. A "/file/name" pattern is replaced by its
contents; a "<a href="DATABASE_README.html">type:table</a>" lookup table is matched when a table entry
matches a lookup string (the lookup result is ignored). Continue
-long lines by starting the next line with whitespace. </p>
+long lines by starting the next line with whitespace. Specify
+"!pattern" to exclude an address or network block from the list.
+The form "!/file/name" is supported only in Postfix version 2.4 and
+later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the <a href="postconf.5.html#smtpd_sasl_exceptions_networks">smtpd_sasl_exceptions_networks</a> value, and in
"/file/name" pattern is replaced by its contents; a "<a href="DATABASE_README.html">type:table</a>"
lookup table is matched when a table entry matches a lookup string
(the lookup result is ignored). Continue long lines by starting
-the next line with whitespace. </p>
+the next line with whitespace. Specify "!pattern" to exclude a host
+or domain name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
See also the <a href="VIRTUAL_README.html">VIRTUAL_README</a> and <a href="ADDRESS_CLASS_README.html">ADDRESS_CLASS_README</a> documents
.PP
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace.
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later.
.PP
This feature is available in Postfix 2.2 and later.
.SH authorized_mailq_users (default: static:anyone)
.PP
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace.
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a user name from the list. The form "!/file/name" is
+supported only in Postfix version 2.4 and later.
.PP
This feature is available in Postfix 2.2 and later.
.SH authorized_submit_users (default: static:anyone)
.PP
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to right,
-and the search stops on the first match. Specify "!name" to exclude a
-name from the list. A "/file/name" pattern is replaced by its contents;
+and the search stops on the first match. A "/file/name" pattern is
+replaced by its contents;
a "type:table" lookup table is matched when a name matches a lookup key
(the lookup result is ignored). Continue long lines by starting the
-next line with whitespace.
+next line with whitespace. Specify "!pattern" to exclude a user
+name from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later.
.PP
Example:
.PP
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace.
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later.
.PP
Note: IP version 6 address information must be specified inside
[] in the authorized_verp_clients value, and in files
.PP
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace.
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later.
.PP
Examples:
.PP
.PP
The list is matched left to right, and the search stops on the
first match. Specify "!pattern" to exclude an address or network
-block from the list.
+block from the list. The form "!/file/name" is supported only
+in Postfix version 2.4 and later.
.PP
Note: IP version 6 address information must be specified inside
[] in the mynetworks value, and in files specified with
table lookup is used instead.
.PP
Patterns are separated by whitespace and/or commas. In order to
-reverse the result, precede a non-file name pattern with an
-exclamation point (!).
+reverse the result, precede a pattern with an
+exclamation point (!). The form "!/file/name" is supported only
+in Postfix version 2.4 and later.
.PP
Example:
.PP
Continue long lines by starting the next line with whitespace. A
"/file/name" pattern is replaced by its contents; a "type:table"
lookup table is matched when a (parent) domain appears as lookup
-key.
+key. Specify "!pattern" to exclude a domain from the list. The form
+"!/file/name" is supported only in Postfix version 2.4 and later.
.SH relay_domains_reject_code (default: 554)
The numerical Postfix SMTP server response code when a client
request is rejected by the reject_unauth_destination recipient
.PP
Specify mechanism names, "/file/name" patterns or "type:table"
lookup tables. The right-hand side result from "type:table" lookups
-is ignored.
+is ignored. Specify "!pattern" to exclude a mechanism name from the
+list. The form "!/file/name" is supported only in Postfix version
+2.4 and later.
.PP
This feature is available in Postfix 2.2 and later.
.PP
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace.
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later.
.PP
Note: IP version 6 address information must be specified inside
[] in the smtpd_authorized_verp_clients value, and in
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace.
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later.
.PP
Note: IP version 6 address information must be specified inside
[] in the smtpd_authorized_xclient_hosts value, and in
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace.
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later.
.PP
Note: IP version 6 address information must be specified inside
[] in the smtpd_authorized_xforward_hosts value, and in
"type:table" patterns. A "/file/name" pattern is replaced by its
contents; a "type:table" lookup table is matched when a table entry
matches a lookup string (the lookup result is ignored). Continue
-long lines by starting the next line with whitespace.
+long lines by starting the next line with whitespace. Specify
+"!pattern" to exclude an address or network block from the list.
+The form "!/file/name" is supported only in Postfix version 2.4 and
+later.
.PP
Note: IP version 6 address information must be specified inside
[] in the smtpd_sasl_exceptions_networks value, and in
"/file/name" pattern is replaced by its contents; a "type:table"
lookup table is matched when a table entry matches a lookup string
(the lookup result is ignored). Continue long lines by starting
-the next line with whitespace.
+the next line with whitespace. Specify "!pattern" to exclude a host
+or domain name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later.
.PP
See also the VIRTUAL_README and ADDRESS_CLASS_README documents
for further information.
<p>
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
Examples:
<p> The list is matched left to right, and the search stops on the
first match. Specify "!pattern" to exclude an address or network
-block from the list. </p>
+block from the list. The form "!/file/name" is supported only
+in Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the mynetworks value, and in files specified with
<p>
Patterns are separated by whitespace and/or commas. In order to
-reverse the result, precede a non-file name pattern with an
-exclamation point (!).
+reverse the result, precede a pattern with an
+exclamation point (!). The form "!/file/name" is supported only
+in Postfix version 2.4 and later.
</p>
<p>
Continue long lines by starting the next line with whitespace. A
"/file/name" pattern is replaced by its contents; a "type:table"
lookup table is matched when a (parent) domain appears as lookup
-key. </p>
+key. Specify "!pattern" to exclude a domain from the list. The form
+"!/file/name" is supported only in Postfix version 2.4 and later.
+</p>
%PARAM relay_domains_reject_code 554
<p> Specify mechanism names, "/file/name" patterns or "type:table"
lookup tables. The right-hand side result from "type:table" lookups
-is ignored. </p>
+is ignored. Specify "!pattern" to exclude a mechanism name from the
+list. The form "!/file/name" is supported only in Postfix version
+2.4 and later. </p>
<p> This feature is available in Postfix 2.2 and later. </p>
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the authorized_verp_clients value, and in files
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the smtpd_authorized_verp_clients value, and in
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the smtpd_authorized_xclient_hosts value, and in
pattern is replaced by its contents; a "type:table" lookup table
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
-with whitespace. </p>
+with whitespace. Specify "!pattern" to exclude an address or network
+block from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the smtpd_authorized_xforward_hosts value, and in
"type:table" patterns. A "/file/name" pattern is replaced by its
contents; a "type:table" lookup table is matched when a table entry
matches a lookup string (the lookup result is ignored). Continue
-long lines by starting the next line with whitespace. </p>
+long lines by starting the next line with whitespace. Specify
+"!pattern" to exclude an address or network block from the list.
+The form "!/file/name" is supported only in Postfix version 2.4 and
+later. </p>
<p> Note: IP version 6 address information must be specified inside
<tt>[]</tt> in the smtpd_sasl_exceptions_networks value, and in
"/file/name" pattern is replaced by its contents; a "type:table"
lookup table is matched when a table entry matches a lookup string
(the lookup result is ignored). Continue long lines by starting
-the next line with whitespace. </p>
+the next line with whitespace. Specify "!pattern" to exclude a host
+or domain name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
See also the VIRTUAL_README and ADDRESS_CLASS_README documents
<p>
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a name from the list. The form "!/file/name" is supported
+only in Postfix version 2.4 and later. </p>
<p>
This feature is available in Postfix 2.2 and later.
<p>
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to
-right, and the search stops on the first match. Specify "!name" to
-exclude a name from the list. A "/file/name" pattern is replaced
+right, and the search stops on the first match. A "/file/name"
+pattern is replaced
by its contents; a "type:table" lookup table is matched when a name
matches a lookup key (the lookup result is ignored). Continue long
-lines by starting the next line with whitespace. </p>
+lines by starting the next line with whitespace. Specify "!pattern"
+to exclude a user name from the list. The form "!/file/name" is
+supported only in Postfix version 2.4 and later. </p>
<p>
This feature is available in Postfix 2.2 and later.
<p>
Specify a list of user names, "/file/name" or "type:table" patterns,
separated by commas and/or whitespace. The list is matched left to right,
-and the search stops on the first match. Specify "!name" to exclude a
-name from the list. A "/file/name" pattern is replaced by its contents;
+and the search stops on the first match. A "/file/name" pattern is
+replaced by its contents;
a "type:table" lookup table is matched when a name matches a lookup key
(the lookup result is ignored). Continue long lines by starting the
-next line with whitespace. </p>
+next line with whitespace. Specify "!pattern" to exclude a user
+name from the list. The form "!/file/name" is supported only in
+Postfix version 2.4 and later. </p>
<p>
Example:
cleanup_map11.c cleanup_map1n.c cleanup_masquerade.c \
cleanup_out_recipient.c cleanup_init.c cleanup_api.c \
cleanup_addr.c cleanup_bounce.c cleanup_milter.c \
- cleanup_body_region.c
+ cleanup_body_edit.c cleanup_region.c
OBJS = cleanup.o cleanup_out.o cleanup_envelope.o cleanup_message.o \
cleanup_extracted.o cleanup_state.o cleanup_rewrite.o \
cleanup_map11.o cleanup_map1n.o cleanup_masquerade.o \
cleanup_out_recipient.o cleanup_init.o cleanup_api.o \
cleanup_addr.o cleanup_bounce.o cleanup_milter.o \
- cleanup_body_region.o
+ cleanup_body_edit.o cleanup_region.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
mv junk cleanup_masquerade.o
CLEANUP_MILTER_OBJS = cleanup_state.o cleanup_out.o cleanup_addr.o \
- cleanup_out_recipient.o cleanup_body_region.o
+ cleanup_out_recipient.o cleanup_body_edit.o cleanup_region.o
cleanup_milter: cleanup_milter.o $(CLEANUP_MILTER_OBJS) $(LIBS)
mv cleanup_milter.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(CLEANUP_MILTER_OBJS) $(LIBS) $(SYSLIBS)
cleanup_milter_test5 cleanup_milter_test6 cleanup_milter_test7 \
cleanup_milter_test8 cleanup_milter_test9 cleanup_milter_test10a \
cleanup_milter_test10b cleanup_milter_test10c cleanup_milter_test10d \
- cleanup_milter_test10e
+ cleanup_milter_test10e cleanup_milter_test11
root_tests:
bug_tests: bug1_test bug2_test
+../postcat/postcat:
+ cd ../postcat; make
+
bug1_test: cleanup_milter bug1.file bug1.in bug1.ref bug1.text.ref \
../postcat/postcat
cp bug1.file bug1.file.tmp
# Test queue file editing routines.
cleanup_milter_test: cleanup_milter test-queue-file cleanup_milter.in1 \
- cleanup_milter.ref1 test-queue-file ../postcat/postcat
+ cleanup_milter.ref1 ../postcat/postcat
cp test-queue-file test-queue-file.tmp
chmod u+w test-queue-file.tmp
./cleanup_milter <cleanup_milter.in1
rm -f test-queue-file.tmp cleanup_milter.tmp
cleanup_milter_test2: cleanup_milter test-queue-file2 cleanup_milter.in2 \
- cleanup_milter.ref2 test-queue-file2 ../postcat/postcat
+ cleanup_milter.ref2 ../postcat/postcat
cp test-queue-file2 test-queue-file2.tmp
chmod u+w test-queue-file2.tmp
./cleanup_milter <cleanup_milter.in2
rm -f test-queue-file2.tmp cleanup_milter.tmp
cleanup_milter_test3: cleanup_milter test-queue-file3 cleanup_milter.in3 \
- cleanup_milter.ref3 test-queue-file3 ../postcat/postcat
+ cleanup_milter.ref3 ../postcat/postcat
cp test-queue-file3 test-queue-file3.tmp
chmod u+w test-queue-file3.tmp
./cleanup_milter <cleanup_milter.in3
rm -f test-queue-file4.tmp cleanup_milter.tmp
cleanup_milter_test5: cleanup_milter test-queue-file5 cleanup_milter.in5 \
- cleanup_milter.ref5 test-queue-file5 ../postcat/postcat
+ cleanup_milter.ref5 ../postcat/postcat
cp test-queue-file5 test-queue-file5.tmp
chmod u+w test-queue-file5.tmp
./cleanup_milter <cleanup_milter.in5
rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6b: cleanup_milter test-queue-file6 cleanup_milter.in6b \
- cleanup_milter.ref6b test-queue-file6 ../postcat/postcat
+ cleanup_milter.ref6b ../postcat/postcat
cp test-queue-file6 test-queue-file6.tmp
chmod u+w test-queue-file6.tmp
./cleanup_milter <cleanup_milter.in6b
rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6c: cleanup_milter test-queue-file6 cleanup_milter.in6c \
- cleanup_milter.ref6c test-queue-file6 ../postcat/postcat
+ cleanup_milter.ref6c ../postcat/postcat
cp test-queue-file6 test-queue-file6.tmp
chmod u+w test-queue-file6.tmp
./cleanup_milter <cleanup_milter.in6c
rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test7: cleanup_milter test-queue-file7 cleanup_milter.in7 \
- cleanup_milter.ref7 test-queue-file7 ../postcat/postcat
+ cleanup_milter.ref7 ../postcat/postcat
cp test-queue-file7 test-queue-file7.tmp
chmod u+w test-queue-file7.tmp
./cleanup_milter <cleanup_milter.in7
rm -f test-queue-file7.tmp cleanup_milter.tmp
cleanup_milter_test8: cleanup_milter test-queue-file8 cleanup_milter.in8 \
- cleanup_milter.ref8 test-queue-file8 ../postcat/postcat
+ cleanup_milter.ref8 ../postcat/postcat
cp test-queue-file8 test-queue-file8.tmp
chmod u+w test-queue-file8.tmp
./cleanup_milter <cleanup_milter.in8
rm -f test-queue-file8.tmp cleanup_milter.tmp
cleanup_milter_test9: cleanup_milter test-queue-file9 cleanup_milter.in9 \
- cleanup_milter.ref9 test-queue-file9 ../postcat/postcat
+ cleanup_milter.ref9 ../postcat/postcat
cp test-queue-file9 test-queue-file9.tmp
chmod u+w test-queue-file9.tmp
./cleanup_milter <cleanup_milter.in9
rm -f test-queue-file9.tmp cleanup_milter.tmp
cleanup_milter_test10a: cleanup_milter test-queue-file10 cleanup_milter.in10a \
- cleanup_milter.ref10a test-queue-file10 ../postcat/postcat
+ cleanup_milter.ref10a ../postcat/postcat
cp test-queue-file10 test-queue-file10.tmp
chmod u+w test-queue-file10.tmp
./cleanup_milter <cleanup_milter.in10a
rm -f test-queue-file10.tmp cleanup_milter.tmp
cleanup_milter_test10b: cleanup_milter test-queue-file10 cleanup_milter.in10b \
- cleanup_milter.ref10b test-queue-file10 ../postcat/postcat
+ cleanup_milter.ref10b ../postcat/postcat
cp test-queue-file10 test-queue-file10.tmp
chmod u+w test-queue-file10.tmp
./cleanup_milter <cleanup_milter.in10b
rm -f test-queue-file10.tmp cleanup_milter.tmp
cleanup_milter_test10c: cleanup_milter test-queue-file10 cleanup_milter.in10c \
- cleanup_milter.ref10c test-queue-file10 ../postcat/postcat
+ cleanup_milter.ref10c ../postcat/postcat
cp test-queue-file10 test-queue-file10.tmp
chmod u+w test-queue-file10.tmp
./cleanup_milter <cleanup_milter.in10c
rm -f test-queue-file10.tmp cleanup_milter.tmp
cleanup_milter_test10d: cleanup_milter test-queue-file10 cleanup_milter.in10c \
- cleanup_milter.ref10d test-queue-file10 ../postcat/postcat
+ cleanup_milter.ref10d ../postcat/postcat
cp test-queue-file10 test-queue-file10.tmp
chmod u+w test-queue-file10.tmp
./cleanup_milter <cleanup_milter.in10d
rm -f test-queue-file10.tmp cleanup_milter.tmp
cleanup_milter_test10e: cleanup_milter test-queue-file10 cleanup_milter.in10c \
- cleanup_milter.ref10e test-queue-file10 ../postcat/postcat
+ cleanup_milter.ref10e ../postcat/postcat
cp test-queue-file10 test-queue-file10.tmp
chmod u+w test-queue-file10.tmp
./cleanup_milter <cleanup_milter.in10e
diff cleanup_milter.ref10e cleanup_milter.tmp
rm -f test-queue-file10.tmp cleanup_milter.tmp
+cleanup_milter_test11: cleanup_milter test-queue-file11 cleanup_milter.in11 \
+ cleanup_milter.ref11 ../postcat/postcat
+ cp test-queue-file11 test-queue-file11.tmp
+ chmod u+w test-queue-file11.tmp
+ ./cleanup_milter <cleanup_milter.in11
+ ../postcat/postcat -ov test-queue-file11.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref11 cleanup_milter.tmp
+ rm -f test-queue-file11.tmp cleanup_milter.tmp
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
cleanup_api.o: ../../include/vstring.h
cleanup_api.o: cleanup.h
cleanup_api.o: cleanup_api.c
-cleanup_body_region.o: ../../include/argv.h
-cleanup_body_region.o: ../../include/been_here.h
-cleanup_body_region.o: ../../include/cleanup_user.h
-cleanup_body_region.o: ../../include/dict.h
-cleanup_body_region.o: ../../include/header_opts.h
-cleanup_body_region.o: ../../include/htable.h
-cleanup_body_region.o: ../../include/mail_conf.h
-cleanup_body_region.o: ../../include/mail_stream.h
-cleanup_body_region.o: ../../include/maps.h
-cleanup_body_region.o: ../../include/match_list.h
-cleanup_body_region.o: ../../include/match_ops.h
-cleanup_body_region.o: ../../include/milter.h
-cleanup_body_region.o: ../../include/mime_state.h
-cleanup_body_region.o: ../../include/msg.h
-cleanup_body_region.o: ../../include/mymalloc.h
-cleanup_body_region.o: ../../include/nvtable.h
-cleanup_body_region.o: ../../include/rec_type.h
-cleanup_body_region.o: ../../include/record.h
-cleanup_body_region.o: ../../include/resolve_clnt.h
-cleanup_body_region.o: ../../include/string_list.h
-cleanup_body_region.o: ../../include/sys_defs.h
-cleanup_body_region.o: ../../include/tok822.h
-cleanup_body_region.o: ../../include/vbuf.h
-cleanup_body_region.o: ../../include/vstream.h
-cleanup_body_region.o: ../../include/vstring.h
-cleanup_body_region.o: cleanup.h
-cleanup_body_region.o: cleanup_body_region.c
+cleanup_body_edit.o: ../../include/argv.h
+cleanup_body_edit.o: ../../include/been_here.h
+cleanup_body_edit.o: ../../include/cleanup_user.h
+cleanup_body_edit.o: ../../include/dict.h
+cleanup_body_edit.o: ../../include/header_opts.h
+cleanup_body_edit.o: ../../include/htable.h
+cleanup_body_edit.o: ../../include/mail_conf.h
+cleanup_body_edit.o: ../../include/mail_stream.h
+cleanup_body_edit.o: ../../include/maps.h
+cleanup_body_edit.o: ../../include/match_list.h
+cleanup_body_edit.o: ../../include/match_ops.h
+cleanup_body_edit.o: ../../include/milter.h
+cleanup_body_edit.o: ../../include/mime_state.h
+cleanup_body_edit.o: ../../include/msg.h
+cleanup_body_edit.o: ../../include/mymalloc.h
+cleanup_body_edit.o: ../../include/nvtable.h
+cleanup_body_edit.o: ../../include/rec_type.h
+cleanup_body_edit.o: ../../include/record.h
+cleanup_body_edit.o: ../../include/resolve_clnt.h
+cleanup_body_edit.o: ../../include/string_list.h
+cleanup_body_edit.o: ../../include/sys_defs.h
+cleanup_body_edit.o: ../../include/tok822.h
+cleanup_body_edit.o: ../../include/vbuf.h
+cleanup_body_edit.o: ../../include/vstream.h
+cleanup_body_edit.o: ../../include/vstring.h
+cleanup_body_edit.o: cleanup.h
+cleanup_body_edit.o: cleanup_body_edit.c
cleanup_bounce.o: ../../include/argv.h
cleanup_bounce.o: ../../include/attr.h
cleanup_bounce.o: ../../include/been_here.h
cleanup_out_recipient.o: ../../include/vstring.h
cleanup_out_recipient.o: cleanup.h
cleanup_out_recipient.o: cleanup_out_recipient.c
+cleanup_region.o: ../../include/argv.h
+cleanup_region.o: ../../include/been_here.h
+cleanup_region.o: ../../include/cleanup_user.h
+cleanup_region.o: ../../include/dict.h
+cleanup_region.o: ../../include/header_opts.h
+cleanup_region.o: ../../include/htable.h
+cleanup_region.o: ../../include/mail_conf.h
+cleanup_region.o: ../../include/mail_stream.h
+cleanup_region.o: ../../include/maps.h
+cleanup_region.o: ../../include/match_list.h
+cleanup_region.o: ../../include/match_ops.h
+cleanup_region.o: ../../include/milter.h
+cleanup_region.o: ../../include/mime_state.h
+cleanup_region.o: ../../include/msg.h
+cleanup_region.o: ../../include/mymalloc.h
+cleanup_region.o: ../../include/nvtable.h
+cleanup_region.o: ../../include/resolve_clnt.h
+cleanup_region.o: ../../include/string_list.h
+cleanup_region.o: ../../include/sys_defs.h
+cleanup_region.o: ../../include/tok822.h
+cleanup_region.o: ../../include/vbuf.h
+cleanup_region.o: ../../include/vstream.h
+cleanup_region.o: ../../include/vstring.h
+cleanup_region.o: cleanup.h
+cleanup_region.o: cleanup_region.c
cleanup_rewrite.o: ../../include/argv.h
cleanup_rewrite.o: ../../include/attr.h
cleanup_rewrite.o: ../../include/been_here.h
BH_TABLE *dups; /* recipient dup filter */
void (*action) (struct CLEANUP_STATE *, int, const char *, ssize_t);
off_t data_offset; /* start of message content */
+ off_t body_offset; /* start of body content */
off_t xtra_offset; /* start of extra segment */
off_t cont_length; /* length including Milter edits */
off_t append_rcpt_pt_offset; /* append recipient here */
/*
* Support for Milter body replacement requests.
*/
- struct CLEANUP_BODY_REGION *body_regions;
- struct CLEANUP_BODY_REGION *curr_body_region;
- off_t body_write_offs; /* body write position */
+ struct CLEANUP_REGION *free_regions;/* unused regions */
+ struct CLEANUP_REGION *body_regions;/* regions with body content */
+ struct CLEANUP_REGION *curr_body_region;
} CLEANUP_STATE;
/*
&& (s)->errs == 0 && ((s)->flags & CLEANUP_FLAG_DISCARD) == 0)
/*
- * cleanup_body_region.c
+ * cleanup_body_edit.c
*/
-typedef struct CLEANUP_BODY_REGION {
+typedef struct CLEANUP_REGION {
off_t start; /* start of region */
off_t len; /* length or zero (open-ended) */
- struct CLEANUP_BODY_REGION *next;
-} CLEANUP_BODY_REGION;
-
-extern int cleanup_body_region_start(CLEANUP_STATE *);
-extern int cleanup_body_region_write(CLEANUP_STATE *, int, VSTRING *);
-extern int cleanup_body_region_finish(CLEANUP_STATE *);
-extern void cleanup_body_region_free(CLEANUP_STATE *);
+ off_t write_offs; /* write offset */
+ struct CLEANUP_REGION *next; /* linkage */
+} CLEANUP_REGION;
+
+extern void cleanup_region_init(CLEANUP_STATE *);
+extern CLEANUP_REGION *cleanup_region_open(CLEANUP_STATE *, ssize_t);
+extern void cleanup_region_close(CLEANUP_STATE *, CLEANUP_REGION *);
+extern CLEANUP_REGION *cleanup_region_return(CLEANUP_STATE *, CLEANUP_REGION *);
+extern void cleanup_region_done(CLEANUP_STATE *);
+
+extern int cleanup_body_edit_start(CLEANUP_STATE *);
+extern int cleanup_body_edit_write(CLEANUP_STATE *, int, VSTRING *);
+extern int cleanup_body_edit_finish(CLEANUP_STATE *);
+extern void cleanup_body_edit_free(CLEANUP_STATE *);
/* LICENSE
/* .ad
--- /dev/null
+/*++
+/* NAME
+/* cleanup_body_edit 3
+/* SUMMARY
+/* edit body content
+/* SYNOPSIS
+/* #include "cleanup.h"
+/*
+/* int cleanup_body_edit_start(state)
+/* CLEANUP_STATE *state;
+/*
+/* int cleanup_body_edit_write(state, type, buf)
+/* CLEANUP_STATE *state;
+/* int type;
+/* VSTRING *buf;
+/*
+/* int cleanup_body_edit_finish(state)
+/* CLEANUP_STATE *state;
+/*
+/* void cleanup_body_edit_free(state)
+/* CLEANUP_STATE *state;
+/* DESCRIPTION
+/* This module maintains queue file regions with body content.
+/* Regions are created on the fly, and can be reused multiple
+/* times. This module must not be called until the queue file
+/* is complete, and there must be no other read/write access
+/* to the queue file between the cleanup_body_edit_start() and
+/* cleanup_body_edit_finish() calls.
+/*
+/* cleanup_body_edit_start() performs initialization and sets
+/* the queue file write pointer to the start of the first body
+/* region.
+/*
+/* cleanup_body_edit_write() adds a queue file record to the
+/* queue file. When the current body region fills up, some
+/* unused region is reused, or a new region is created.
+/*
+/* cleanup_body_edit_finish() makes some final adjustments
+/* after the last body content record is written.
+/*
+/* cleanup_body_edit_free() frees up memory that was allocated
+/* by cleanup_body_edit_start() and cleanup_body_edit_write().
+/*
+/* Arguments:
+/* .IP state
+/* Queue file and message processing state. This state is updated
+/* as records are processed and as errors happen.
+/* .IP type
+/* Record type.
+/* .IP buf
+/* Record content.
+/* 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 <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <rec_type.h>
+#include <record.h>
+
+/* Application-specific. */
+
+#include <cleanup.h>
+
+#define LEN(s) VSTRING_LEN(s)
+
+static int cleanup_body_edit_ptr_rec_len;
+
+/* cleanup_body_edit_start - rewrite body region pool */
+
+int cleanup_body_edit_start(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_body_edit_start";
+ CLEANUP_REGION *curr_rp;
+
+ /*
+ * Calculate the payload size sans body.
+ */
+ state->cont_length = state->body_offset - state->data_offset;
+
+ /*
+ * One-time initialization.
+ */
+ if (state->body_regions == 0) {
+ REC_SPACE_NEED(REC_TYPE_PTR_PAYL_SIZE, cleanup_body_edit_ptr_rec_len);
+ cleanup_region_init(state);
+ }
+
+ /*
+ * Return all body regions to the free pool.
+ */
+ cleanup_region_return(state, state->body_regions);
+
+ /*
+ * Select the first region. XXX This will usally be the original body
+ * segment, but we must not count on that. Region assignments may change
+ * when header editing also uses queue file regions. XXX We don't really
+ * know if the first region will be large enough to hold the first body
+ * text record, but this problem is so rare that we will not complicate
+ * the code for it. If the first region is too small then we will simply
+ * waste it.
+ */
+ curr_rp = state->curr_body_region = state->body_regions =
+ cleanup_region_open(state, cleanup_body_edit_ptr_rec_len);
+
+ /*
+ * Link the first body region to the last message header.
+ */
+ if (vstream_fseek(state->dst, state->append_hdr_pt_offset, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ state->append_hdr_pt_target = curr_rp->start;
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) state->append_hdr_pt_target);
+
+ /*
+ * Move the file write pointer to the start of the current region.
+ */
+ if (vstream_ftell(state->dst) != curr_rp->start
+ && vstream_fseek(state->dst, curr_rp->start, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ return (0);
+}
+
+/* cleanup_body_edit_write - add record to body region pool */
+
+int cleanup_body_edit_write(CLEANUP_STATE *state, int rec_type,
+ VSTRING *buf)
+{
+ const char *myname = "cleanup_body_edit_write";
+ CLEANUP_REGION *curr_rp = state->curr_body_region;
+ CLEANUP_REGION *next_rp;
+ off_t space_used;
+ ssize_t space_needed;
+ ssize_t rec_len;
+
+ if (msg_verbose)
+ msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
+ myname, (long) curr_rp->write_offs, (long) LEN(buf),
+ (long) curr_rp->start, (long) curr_rp->len);
+
+ /*
+ * Switch to the next body region if we filled up the current one (we
+ * always append to an open-ended region). Besides space to write the
+ * specified record, we need to leave space for a final pointer record
+ * that will link this body region to the next region or to the content
+ * terminator record.
+ */
+ if (curr_rp->len > 0) {
+ space_used = curr_rp->write_offs - curr_rp->start;
+ REC_SPACE_NEED(LEN(buf), rec_len);
+ space_needed = rec_len + cleanup_body_edit_ptr_rec_len;
+ if (space_needed > curr_rp->len - space_used) {
+
+ /*
+ * Update the payload size. Connect the filled up body region to
+ * its successor.
+ */
+ state->cont_length += space_used;
+ next_rp = cleanup_region_open(state, space_needed);
+ if (msg_verbose)
+ msg_info("%s: link %ld -> %ld", myname,
+ (long) curr_rp->write_offs, (long) next_rp->start);
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) next_rp->start);
+ curr_rp->write_offs = vstream_ftell(state->dst);
+ cleanup_region_close(state, curr_rp);
+ curr_rp->next = next_rp;
+
+ /*
+ * Select the new body region.
+ */
+ state->curr_body_region = curr_rp = next_rp;
+ if (vstream_fseek(state->dst, curr_rp->start, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ }
+ }
+
+ /*
+ * Finally, output the queue file record.
+ */
+ CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
+ curr_rp->write_offs = vstream_ftell(state->dst);
+
+ return (0);
+}
+
+/* cleanup_body_edit_finish - wrap up body region pool */
+
+int cleanup_body_edit_finish(CLEANUP_STATE *state)
+{
+ CLEANUP_REGION *curr_rp = state->curr_body_region;
+
+ /*
+ * Update the payload size.
+ */
+ state->cont_length += curr_rp->write_offs - curr_rp->start;
+
+ /*
+ * Link the last body region to the content terminator record.
+ */
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) state->xtra_offset);
+ curr_rp->write_offs = vstream_ftell(state->dst);
+ cleanup_region_close(state, curr_rp);
+
+ return (CLEANUP_OUT_OK(state) ? 0 : -1);
+}
+++ /dev/null
-/*++
-/* NAME
-/* cleanup_body_region 3
-/* SUMMARY
-/* manage body content regions
-/* SYNOPSIS
-/* #include "cleanup.h"
-/*
-/* int cleanup_body_region_start(state)
-/* CLEANUP_STATE *state;
-/*
-/* int cleanup_body_region_write(state, type, buf)
-/* CLEANUP_STATE *state;
-/* int type;
-/* VSTRING *buf;
-/*
-/* int cleanup_body_region_finish(state)
-/* CLEANUP_STATE *state;
-/*
-/* void cleanup_body_region_free(state)
-/* CLEANUP_STATE *state;
-/* DESCRIPTION
-/* This module maintains queue file regions with body content.
-/* Regions are created on the fly, and can be reused multiple
-/* times. This module must not be called until the queue file
-/* is complete.
-/*
-/* cleanup_body_region_start() performs initialization and
-/* sets the queue file write pointer to the start of the
-/* first body content segment.
-/*
-/* cleanup_body_region_write() adds a queue file record to the
-/* current queue file. When the current queue file region fills
-/* up, some other region is reused or a new one is created.
-/*
-/* cleanup_body_region_finish() makes some final adjustments
-/* after the last body content record is written.
-/*
-/* cleanup_body_region_free() frees up memory that was allocated
-/* by cleanup_body_region_start() and cleanup_body_region_write().
-/*
-/* Arguments:
-/* .IP state
-/* Queue file and message processing state. This state is updated
-/* as records are processed and as errors happen.
-/* .IP type
-/* Record type.
-/* .IP buf
-/* Record content.
-/* BUGS
-/* Currently, queue file region management is intertwined with
-/* body content management. Eventually the two should be
-/* decoupled, so that space freed up after body editing may
-/* be reused for header updates and vice versa.
-/* 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 <msg.h>
-#include <mymalloc.h>
-#include <vstream.h>
-#include <vstring.h>
-
-/* Global library. */
-
-#include <rec_type.h>
-#include <record.h>
-
-/* Application-specific. */
-
-#include <cleanup.h>
-
-#define LEN(s) VSTRING_LEN(s)
-
-/* cleanup_body_region_alloc - create body content region */
-
-static CLEANUP_BODY_REGION *cleanup_body_region_alloc(off_t start, off_t len)
-{
- CLEANUP_BODY_REGION *rp;
-
- rp = (CLEANUP_BODY_REGION *) mymalloc(sizeof(*rp));
- rp->start = start;
- rp->len = len;
- rp->next = 0;
-
- return (rp);
-}
-
-/* cleanup_body_region_free - destroy all body content regions */
-
-void cleanup_body_region_free(CLEANUP_STATE *state)
-{
- CLEANUP_BODY_REGION *rp;
- CLEANUP_BODY_REGION *next;
-
- for (rp = state->body_regions; rp != 0; rp = next) {
- next = rp->next;
- myfree((char *) rp);
- }
-}
-
-/* cleanup_body_region_start - rewrite body buffer pool */
-
-int cleanup_body_region_start(CLEANUP_STATE *state)
-{
- const char *myname = "cleanup_body_region_write";
-
- /*
- * Calculate the payload size sans body.
- */
- state->cont_length = state->append_hdr_pt_target - state->data_offset;
-
- /*
- * Craft the first body region on the fly, from circumstantial evidence.
- */
- if (state->body_regions == 0)
- state->body_regions =
- cleanup_body_region_alloc(state->append_hdr_pt_target,
- state->xtra_offset - state->append_hdr_pt_target);
-
- /*
- * Select the first region and initialize the write position.
- */
- state->curr_body_region = state->body_regions;
- state->body_write_offs = state->curr_body_region->start;
-
- /*
- * Move the file write pointer to the start of the current region.
- */
- if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
- msg_warn("%s: seek file %s: %m", myname, cleanup_path);
- return (-1);
- }
- return (0);
-}
-
-/* cleanup_body_region_write - add record to body buffer pool */
-
-int cleanup_body_region_write(CLEANUP_STATE *state, int rec_type,
- VSTRING *buf)
-{
- const char *myname = "cleanup_body_region_write";
- CLEANUP_BODY_REGION *rp = state->curr_body_region;
- off_t used;
- ssize_t rec_len;
- off_t start;
-
- if (msg_verbose)
- msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
- myname, (long) state->body_write_offs, (long) LEN(buf),
- (long) rp->start, (long) rp->len);
-
- /*
- * Switch to the next body region if we filled up the current one (we
- * always append to an open-ended region). Besides space to write the
- * specified record, we need to leave space for a final pointer record
- * that will link this body region to the next region or to the content
- * terminator record.
- */
- REC_SPACE_NEED(LEN(buf), rec_len);
- while (rp->len > 0 && (used = state->body_write_offs - rp->start,
- rec_len + REC_TYPE_PTR_SIZE > rp->len - used)) {
-
- /*
- * Allocate a new body region if we filled up the last one. A newly
- * allocated region sits at the end of the queue file, and therefore
- * it starts as open ended. We freeze the region size later.
- *
- * Don't use fstat() to figure out where the queue file ends, in case
- * file sizes have magic in them. Instead we seek to the end and then
- * back to where we were. We're not switching body regions often, so
- * this is not performance critical.
- */
- if (rp->next == 0) {
- if ((start = vstream_fseek(state->dst, (off_t) 0, SEEK_END)) < 0) {
- msg_warn("%s: seek file %s: %m", myname, cleanup_path);
- return (-1);
- }
- if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
- msg_warn("%s: seek file %s: %m", myname, cleanup_path);
- return (-1);
- }
- rp->next = cleanup_body_region_alloc(start, 0);
- }
-
- /*
- * Update the payload size and select the new body region.
- */
- state->cont_length += state->body_write_offs - rp->start;
- state->curr_body_region = rp = rp->next;
-
- /*
- * Connect the filled up body region to its successor. By design a
- * region has always space for a final pointer record.
- */
- if (msg_verbose)
- msg_info("%s: link %ld -> %ld", myname,
- (long) state->body_write_offs, (long) rp->start);
- rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
- (long) rp->start);
- if (vstream_fseek(state->dst, rp->start, SEEK_SET) < 0) {
- msg_warn("%s: seek file %s: %m", myname, cleanup_path);
- return (-1);
- }
- }
-
- /*
- * Finally, output the queue file record.
- */
- CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
- state->body_write_offs = vstream_ftell(state->dst);
-
- return (0);
-}
-
-/* cleanup_body_region_finish - wrap up body buffer pool */
-
-int cleanup_body_region_finish(CLEANUP_STATE *state)
-{
- const char *myname = "cleanup_body_region_finish";
- CLEANUP_BODY_REGION *rp;
-
- /*
- * Link the last body region to the content terminator record.
- */
- rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
- (long) state->xtra_offset);
- state->body_write_offs = vstream_ftell(state->dst);
-
- /*
- * Update the payload size.
- */
- rp = state->curr_body_region;
- state->cont_length += state->body_write_offs - rp->start;
-
- /*
- * Freeze the size of the last region if it is still open ended. The next
- * Milter application may append more header records, therefore we must
- * not assume that this region can grow further. Nor can we truncate the
- * queue file to the end of this region, as this region may be followed
- * by headers that were appended by an earlier Milter application.
- *
- * XXX Eventually, split a partially-used region so that the remainder can
- * be returned to a free pool and reused for header updates.
- */
- if (rp->len == 0)
- rp->len = state->body_write_offs - rp->start;
- if (msg_verbose)
- msg_info("%s: freeze start %ld len %ld",
- myname, (long) rp->start, (long) rp->len);
-
- return (CLEANUP_OUT_OK(state) ? 0 : -1);
-}
void cleanup_extracted_finish(CLEANUP_STATE *state)
{
- const char myname[] = "cleanup_extracted_finish";
/*
* On the way out, add the optional automatic BCC recipient.
cleanup_out_format(state, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT, 0L);
if ((state->append_hdr_pt_target = vstream_ftell(state->dst)) < 0)
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
+ state->body_offset = state->append_hdr_pt_target;
}
}
* pointer record. Requirement: the message headers (and body) always end
* in a pointer record.
*/
- while (rec_type != REC_TYPE_PTR && avail_space < REC_TYPE_PTR_SIZE) {
+ while (rec_type != REC_TYPE_PTR && avail_space < REC_TYPE_PTR_PAYL_SIZE) {
/* Read existing text or pointer record. */
if (vstream_fseek(state->dst, read_offset, SEEK_SET) < 0) {
msg_warn("%s: seek file %s: %m", myname, cleanup_path);
*/
switch (cmd) {
case MILTER_BODY_LINE:
- if (cleanup_body_region_write(state, REC_TYPE_NORM, buf) < 0)
+ if (cleanup_body_edit_write(state, REC_TYPE_NORM, buf) < 0)
return (cleanup_milter_error(state, errno));
break;
case MILTER_BODY_START:
VSTRING_RESET(&empty);
- if (cleanup_body_region_start(state) < 0
- || cleanup_body_region_write(state, REC_TYPE_NORM, &empty) < 0)
+ if (cleanup_body_edit_start(state) < 0
+ || cleanup_body_edit_write(state, REC_TYPE_NORM, &empty) < 0)
return (cleanup_milter_error(state, errno));
break;
case MILTER_BODY_END:
- if (cleanup_body_region_finish(state) < 0)
+ if (cleanup_body_edit_finish(state) < 0)
return (cleanup_milter_error(state, errno));
break;
default:
--- /dev/null
+#
+# Replace a non-existent body by a non-empty one.
+#
+#verbose on
+open test-queue-file11.tmp
+
+replbody loremipsum
+replbody loremipsum
+
+close
346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
453 regular_text: Subject: hey!
- 468 pointer_record: 0
+ 468 pointer_record: 485
485 regular_text:
487 pointer_record: 552
552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
453 regular_text: Subject: hey!
- 468 pointer_record: 0
+ 468 pointer_record: 485
485 regular_text:
487 pointer_record: 552
552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
453 regular_text: Subject: hey!
- 468 pointer_record: 0
+ 468 pointer_record: 485
485 regular_text:
487 pointer_record: 552
552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
453 regular_text: Subject: hey!
- 468 pointer_record: 0
+ 468 pointer_record: 485
485 regular_text:
487 pointer_record: 552
552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file11.tmp ***
+ 0 message_size: 358 480 1 0 358
+ 81 message_arrival_time: Thu Jan 18 15:15:42 2007
+ 100 create_time: Thu Jan 18 15:15:48 2007
+ 124 named_attribute: rewrite_context=local
+ 147 sender:
+ 149 named_attribute: log_client_name=localhost
+ 176 named_attribute: log_client_address=127.0.0.1
+ 206 named_attribute: log_message_origin=localhost[127.0.0.1]
+ 247 named_attribute: log_protocol_name=SMTP
+ 271 named_attribute: client_name=localhost
+ 294 named_attribute: reverse_client_name=localhost
+ 325 named_attribute: client_address=127.0.0.1
+ 351 named_attribute: client_address_type=2
+ 374 named_attribute: dsn_orig_rcpt=rfc822;wietse@localhost
+ 413 original_recipient: wietse@localhost
+ 431 recipient: wietse@localhost.example.com
+ 461 pointer_record: 0
+ 478 *** MESSAGE CONTENTS test-queue-file11.tmp ***
+ 480 regular_text: Received: from localhost (localhost [127.0.0.1])
+ 530 regular_text: by foo.example.com (Postfix) with SMTP id 2ADF9290403
+ 586 regular_text: for <wietse@localhost>; Thu, 18 Jan 2007 15:15:42 -0500 (EST)
+ 650 regular_text: Message-Id: <20070118201548.2ADF9290403@foo.example.com>
+ 708 regular_text: Date: Thu, 18 Jan 2007 15:15:42 -0500 (EST)
+ 753 regular_text: From: MAILER-DAEMON
+ 774 regular_text: To: undisclosed-recipients:;
+ 804 pointer_record: 821
+ 821 pointer_record: 842
+ 842 regular_text:
+ 844 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 909 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 976 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 1044 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 1113 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 1182 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 1248 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1316 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1383 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1448 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1522 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1591 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1659 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1726 regular_text: pariatur?\r
+ 1738 regular_text: \r
+ 1741 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1806 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1871 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1939 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 2006 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 2077 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 2144 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 2211 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 2280 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2350 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2416 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2485 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2551 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2612 pointer_record: 838
+ 838 *** HEADER EXTRACTED test-queue-file11.tmp ***
+ 840 *** MESSAGE FILE END test-queue-file11.tmp ***
--- /dev/null
+/*++
+/* NAME
+/* cleanup_region 3
+/* SUMMARY
+/* queue file region manager
+/* SYNOPSIS
+/* #include "cleanup.h"
+/*
+/* void cleanup_region_init(state)
+/* CLEANUP_STATE *state;
+/*
+/* CLEANUP_REGION *cleanup_region_open(state, space_needed)
+/* CLEANUP_STATE *state;
+/* ssize_t space_needed;
+/*
+/* int cleanup_region_close(state, rp)
+/* CLEANUP_STATE *state;
+/* CLEANUP_REGION *rp;
+/*
+/* CLEANUP_REGION *cleanup_region_return(state, rp)
+/* CLEANUP_STATE *state;
+/* CLEANUP_REGION *rp;
+/*
+/* void cleanup_region_done(state)
+/* CLEANUP_STATE *state;
+/* DESCRIPTION
+/* This module maintains queue file regions. Regions are created
+/* on-the-fly and can be reused multiple times. Each region
+/* structure consists of a file offset, a length (0 for an
+/* open-ended region at the end of the file), a write offset
+/* (maintained by the caller), and list linkage. Region
+/* boundaries are not enforced by this module. It is up to the
+/* caller to ensure that they stay within bounds.
+/*
+/* cleanup_region_init() performs mandatory initialization and
+/* overlays an initial region structure over an already existing
+/* queue file. This function must not be called before the
+/* queue file is complete.
+/*
+/* cleanup_region_open() opens an existing region or creates
+/* a new region that can accomodate at least the specified
+/* amount of space. A new region is an open-ended region at
+/* the end of the file; it must be closed (see next) before
+/* unrelated data can be appended to the same file.
+/*
+/* cleanup_region_close() indicates that a region will not be
+/* updated further. With an open-ended region, the region's
+/* end is frozen just before the caller-maintained write offset.
+/* With a close-ended region, unused space (beginning at the
+/* caller-maintained write offset) may be returned to the free
+/* pool.
+/*
+/* cleanup_region_return() returns a list of regions to the
+/* free pool, and returns a null pointer. To avoid fragmentation,
+/* adjacent free regions may be coalesced together.
+/*
+/* cleanup_region_done() destroys all in-memory information
+/* that was allocated for administering queue file regions.
+/*
+/* Arguments:
+/* .IP state
+/* Queue file and message processing state. This state is
+/* updated as records are processed and as errors happen.
+/* .IP space_needed
+/* The minimum region size needed.
+/* 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 <sys/stat.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+
+/* Application-specific. */
+
+#include <cleanup.h>
+
+/* cleanup_region_alloc - create queue file region */
+
+static CLEANUP_REGION *cleanup_region_alloc(off_t start, off_t len)
+{
+ CLEANUP_REGION *rp;
+
+ rp = (CLEANUP_REGION *) mymalloc(sizeof(*rp));
+ rp->write_offs = rp->start = start;
+ rp->len = len;
+ rp->next = 0;
+
+ return (rp);
+}
+
+/* cleanup_region_free - destroy region list */
+
+static CLEANUP_REGION *cleanup_region_free(CLEANUP_REGION *regions)
+{
+ CLEANUP_REGION *rp;
+ CLEANUP_REGION *next;
+
+ for (rp = regions; rp != 0; rp = next) {
+ next = rp->next;
+ myfree((char *) rp);
+ }
+ return (0);
+}
+
+/* cleanup_region_init - create initial region overlay */
+
+void cleanup_region_init(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_region_init";
+
+ /*
+ * Sanity check.
+ */
+ if (state->free_regions != 0 || state->body_regions != 0)
+ msg_panic("%s: repeated call", myname);
+
+ /*
+ * Craft the first regions on the fly, from circumstantial evidence.
+ */
+ state->body_regions =
+ cleanup_region_alloc(state->append_hdr_pt_target,
+ state->xtra_offset - state->append_hdr_pt_target);
+ if (msg_verbose)
+ msg_info("%s: body start %ld len %ld",
+ myname, (long) state->body_regions->start, (long) state->body_regions->len);
+}
+
+/* cleanup_region_open - open existing region or create new region */
+
+CLEANUP_REGION *cleanup_region_open(CLEANUP_STATE *state, ssize_t len)
+{
+ const char *myname = "cleanup_region_open";
+ CLEANUP_REGION **rpp;
+ CLEANUP_REGION *rp;
+ struct stat st;
+
+ /*
+ * Find the first region that is large enough, or create a new region.
+ */
+ for (rpp = &state->free_regions; /* see below */ ; rpp = &(rp->next)) {
+
+ /*
+ * Create an open-ended region at the end of the queue file. We
+ * freeze the region size after we stop writing to it. XXX Assume
+ * that fstat() returns a file size that is never less than the file
+ * append offset. It is not a problem if fstat() returns a larger
+ * result; we would just waste some space.
+ */
+ if ((rp = *rpp) == 0) {
+ if (fstat(vstream_fileno(state->dst), &st) < 0)
+ msg_fatal("%s: fstat file %s: %m", myname, cleanup_path);
+ rp = cleanup_region_alloc(st.st_size, 0);
+ break;
+ }
+
+ /*
+ * Reuse an existing region.
+ */
+ if (rp->len >= len) {
+ (*rpp) = rp->next;
+ rp->next = 0;
+ rp->write_offs = rp->start;
+ break;
+ }
+
+ /*
+ * Skip a too small region.
+ */
+ if (msg_verbose)
+ msg_info("%s: skip start %ld len %ld < %ld",
+ myname, (long) rp->start, (long) rp->len, (long) len);
+ }
+ if (msg_verbose)
+ msg_info("%s: done start %ld len %ld",
+ myname, (long) rp->start, (long) rp->len);
+ return (rp);
+}
+
+/* cleanup_region_close - freeze queue file region size */
+
+void cleanup_region_close(CLEANUP_STATE *unused_state, CLEANUP_REGION *rp)
+{
+ const char *myname = "cleanup_region_close";
+
+ /*
+ * If this region is still open ended, freeze the size. If this region is
+ * closed, some future version of this routine may shrink the size and
+ * return the unused portion to the free pool.
+ */
+ if (rp->len == 0)
+ rp->len = rp->write_offs - rp->start;
+ if (msg_verbose)
+ msg_info("%s: freeze start %ld len %ld",
+ myname, (long) rp->start, (long) rp->len);
+}
+
+/* cleanup_region_return - return region list to free pool */
+
+CLEANUP_REGION *cleanup_region_return(CLEANUP_STATE *state, CLEANUP_REGION *rp)
+{
+ CLEANUP_REGION **rpp;
+
+ for (rpp = &state->free_regions; (*rpp) != 0; rpp = &(*rpp)->next)
+ /* void */ ;
+ *rpp = rp;
+ return (0);
+}
+
+/* cleanup_region_done - destroy region metadata */
+
+void cleanup_region_done(CLEANUP_STATE *state)
+{
+ if (state->free_regions != 0)
+ state->free_regions = cleanup_region_free(state->free_regions);
+ if (state->body_regions != 0)
+ state->body_regions = cleanup_region_free(state->body_regions);
+}
state->dups = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD);
state->action = cleanup_envelope;
state->data_offset = -1;
+ state->body_offset = -1;
state->xtra_offset = -1;
state->cont_length = 0;
state->append_rcpt_pt_offset = -1;
state->client_port = 0;
state->milter_ext_from = 0;
state->milter_ext_rcpt = 0;
- state->body_regions = state->curr_body_region = 0;
+ state->free_regions = state->body_regions = state->curr_body_region = 0;
return (state);
}
vstring_free(state->milter_ext_from);
if (state->milter_ext_rcpt)
vstring_free(state->milter_ext_rcpt);
- if (state->body_regions)
- cleanup_body_region_free(state);
+ cleanup_region_done(state);
myfree((char *) state);
}
/* A host name matches a domain list when its name appears in the
/* list of domain patterns, or when any of its parent domains appears
/* in the list of domain patterns. The matching process is case
-/* insensitive. In order to reverse the result, precede a non-file
-/* name pattern with an exclamation point (!).
+/* insensitive. In order to reverse the result, precede a
+/* pattern with an exclamation point (!).
/*
/* domain_list_init() performs initializations. The first argument
/* is the bit-wise OR of zero or more of the following:
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070117"
+#define MAIL_RELEASE_DATE "20070118"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
/* type:name table specification, table lookup is used
/* instead.
/* Patterns are separated by whitespace and/or commas. In
-/* order to reverse the result, precede a non-file name
-/* pattern with an exclamation point (!).
+/* order to reverse the result, precede a pattern with an
+/* exclamation point (!).
/*
/* A host matches a list when its name or address matches
/* a pattern, or when any of its parent domains matches a
./namadr_list 168.100.189.2 dummy 168.100.189.3
./namadr_list '[168.100.189.2]' dummy 168.100.189.2
./namadr_list '[168.100.189.2]' dummy 168.100.189.3
+echo foo !bar baz >junk
+./namadr_list !`pwd`/junk dummy 168.100.189.3
+./namadr_list !`pwd`/junk foo 168.100.189.3
+./namadr_list !`pwd`/junk bar 168.100.189.3
+rm -f junk
+env foo=x ./namadr_list environ:junk foo 168.100.189.3
+env foo=x ./namadr_list environ:junk bar 168.100.189.3
+env foo=x ./namadr_list !environ:junk foo 168.100.189.3
+env foo=x ./namadr_list !environ:junk bar 168.100.189.3
+env foo=x ./namadr_list !!environ:junk foo 168.100.189.3
+env foo=x ./namadr_list !!environ:junk bar 168.100.189.3
dummy/168.100.189.3: NO
dummy/168.100.189.2: YES
dummy/168.100.189.3: NO
+dummy/168.100.189.3: NO
+foo/168.100.189.3: NO
+bar/168.100.189.3: YES
+foo/168.100.189.3: YES
+bar/168.100.189.3: NO
+foo/168.100.189.3: NO
+bar/168.100.189.3: NO
+foo/168.100.189.3: YES
+bar/168.100.189.3: NO
* See also: REC_TYPE_SIZE_FORMAT above.
*/
#define REC_TYPE_PTR_FORMAT "%15ld"
-#define REC_TYPE_PTR_SIZE 15
+#define REC_TYPE_PTR_PAYL_SIZE 15 /* Payload only, excludes record header. */
/*
* Programmatic interface.
#define REC_SPACE_NEED(buflen, reclen) do { \
ssize_t _c, _l; \
- for (_c = 1, _l = (buflen); _l != 0; _l >>= 7U, _c++) \
+ for (_c = 1, _l = (buflen); (_l >>= 7U) != 0; _c++) \
; \
(reclen) = 1 + _c + (buflen); \
} while (0)
/*
/* A string matches a string list when it appears in the list of
/* string patterns. The matching process is case insensitive.
-/* In order to reverse the result, precede a non-file name pattern
-/* with an exclamation point (!).
+/* In order to reverse the result, precede a pattern with an
+/* exclamation point (!).
/*
/* string_list_init() performs initializations. The flags argument
/* is ignored; pattern_list specifies a list of string patterns.
/* is either a string, a file name (in which case the contents
/* of the file are substituted for the file name) or a type:name
/* lookup table specification. In order to reverse the result of
-/* a pattern match, precede a non-file name pattern with an
-/* exclamation point (!).
+/* a pattern match, precede a pattern with an exclamation point (!).
/*
/* match_list_init() performs initializations. The flags argument
/* specifies the bit-wise OR of zero or more of the following:
/* match_list_parse - parse buffer, destroy buffer */
-static ARGV *match_list_parse(ARGV *list, char *string)
+static ARGV *match_list_parse(ARGV *list, char *string, int match)
{
const char *myname = "match_list_parse";
- VSTRING *buf = 0;
+ VSTRING *buf = vstring_alloc(10);
VSTREAM *fp;
const char *delim = " ,\t\r\n";
char *bp = string;
- char *pattern;
- char *map_type_name;
+ char *start;
+ char *item;
char *map_type_name_flags;
/*
- * XXX We do not support ! before /filename, because the file contents
- * are expanded in-line. Fixing this requires separating the operator (!)
- * from its operands (file content) so that the operator can apply to a
- * group of operands.
+ * /filename contents are expanded in-line. To support !/filename we
+ * prepend the negation operator to each item from the file.
*/
- while ((pattern = mystrtok(&bp, delim)) != 0) {
- if (*pattern == '/') { /* /file/name */
- if (buf == 0)
- buf = vstring_alloc(10);
- if ((fp = vstream_fopen(pattern, O_RDONLY, 0)) == 0)
- msg_fatal("%s: open file %s: %m", myname, pattern);
+ while ((start = mystrtok(&bp, delim)) != 0) {
+ for (item = start; *item == '!'; item++)
+ match = !match;
+ if (*item == 0)
+ msg_fatal("%s: no pattern after '!'", myname);
+ if (*item == '/') { /* /file/name */
+ if ((fp = vstream_fopen(item, O_RDONLY, 0)) == 0)
+ msg_fatal("%s: open file %s: %m", myname, item);
while (vstring_fgets(buf, fp))
if (vstring_str(buf)[0] != '#')
- list = match_list_parse(list, vstring_str(buf));
+ list = match_list_parse(list, vstring_str(buf), match);
if (vstream_fclose(fp))
- msg_fatal("%s: read file %s: %m", myname, pattern);
- } else if (MATCH_DICTIONARY(pattern)) { /* type:table */
- if (buf == 0)
- buf = vstring_alloc(10);
+ msg_fatal("%s: read file %s: %m", myname, item);
+ } else if (MATCH_DICTIONARY(item)) { /* type:table */
#define OPEN_FLAGS O_RDONLY
#define DICT_FLAGS (DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX)
#define STR(x) vstring_str(x)
- for (map_type_name = pattern; *map_type_name == '!'; map_type_name++)
- /* void */ ;
- vstring_sprintf(buf, "%s(%o,%s)", pattern, OPEN_FLAGS,
- dict_flags_str(DICT_FLAGS));
- map_type_name_flags = STR(buf) + (map_type_name - pattern);
+ vstring_sprintf(buf, "%s%s(%o,%s)", match ? "" : "!",
+ item, OPEN_FLAGS, dict_flags_str(DICT_FLAGS));
+ map_type_name_flags = STR(buf) + (match == 0);
if (dict_handle(map_type_name_flags) == 0)
dict_register(map_type_name_flags,
- dict_open(map_type_name, OPEN_FLAGS, DICT_FLAGS));
+ dict_open(item, OPEN_FLAGS, DICT_FLAGS));
argv_add(list, STR(buf), (char *) 0);
} else { /* other pattern */
- argv_add(list, pattern, (char *) 0);
+ argv_add(list, match ? item :
+ STR(vstring_sprintf(buf, "!%s", item)), (char *) 0);
}
}
- if (buf)
- vstring_free(buf);
+ vstring_free(buf);
return (list);
}
list->match_func[i] = va_arg(ap, MATCH_LIST_FN);
va_end(ap);
+#define DO_MATCH 1
+
saved_patterns = mystrdup(patterns);
- list->patterns = match_list_parse(argv_alloc(1), saved_patterns);
+ list->patterns = match_list_parse(argv_alloc(1), saved_patterns, DO_MATCH);
argv_terminate(list->patterns);
myfree(saved_patterns);
return (list);