mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 21:55:20 +00:00
postfix-3.2-20170122
This commit is contained in:
committed by
Viktor Dukhovni
parent
7a51b3ef05
commit
e69c67e916
@@ -22845,3 +22845,21 @@ Apologies for any names omitted.
|
||||
compatibility, for check_sender_access and check_recipient_access.
|
||||
This now uses 'user@' lookup support in the mail_addr_find()
|
||||
engine. File: global/mail_addr_find.*, smtpd/smtpd_check.c.
|
||||
|
||||
20170122
|
||||
|
||||
Cleanup: separated the database query form from the address
|
||||
form that is input to mail_addr_find_() or mail_addr_map*(),
|
||||
in attempt to make code more obviously correct. Files:
|
||||
global/mail_addr_find.c, global/mail_addr_map.c.
|
||||
|
||||
Abandoned an experiment that used internal-form queries for
|
||||
all maps, because it would be very difficult to test. The
|
||||
tests inputs would have to compensate for multiple levels
|
||||
of unquoting by postmap, C compilers, or shell interpreters.
|
||||
|
||||
Cleanup: moved the backwards-compatibility lookup strategy
|
||||
(try the external address form first, then the internal
|
||||
address form if it is different) inside the loop that
|
||||
iterates over full and partial address forms. File:
|
||||
global/mail_addr_find.c.
|
||||
|
@@ -8,15 +8,11 @@ Wish list:
|
||||
|
||||
Enable external-form lookups for smtpd access maps.
|
||||
|
||||
Enable caching in quote_822_local.
|
||||
|
||||
Quoting: in smtp_map11, don't convert to external.
|
||||
|
||||
Make the address substring generation ("strategy") suitable
|
||||
for dict-based applications such as access(5) maps or local
|
||||
aliases. Either that, or do some serious surgery on the
|
||||
dict-based mechanisms. For access(5) maps this requires a
|
||||
localpart[+ext]@ query that comes after the domain queries.
|
||||
Convert postalias(1) to store external-form keys, and convert
|
||||
aliases(5) to perform external-first lookup with fallback to
|
||||
internal form, to make it consistent with the rest of Postfix.
|
||||
In several years we may remove the internal-form fallbacks
|
||||
with a compatibility_level safety net.
|
||||
|
||||
In the bounce daemon, set util_utf8_enable if returning an
|
||||
SMTPUTF8 message.
|
||||
@@ -37,18 +33,6 @@ Wish list:
|
||||
RHS. This will not preserve trailing comments in lines that
|
||||
are modified with "postconf -e" and the like.
|
||||
|
||||
The cleanup daemon searches canonical_maps and virtual_alias_maps
|
||||
with quoted address forms. The address local part should
|
||||
be in unquoted form before it is split into name and
|
||||
extension. Note, however, that although quoting is done
|
||||
over the entire localpart, unquoting is not simply a matter
|
||||
of removing the outer quotes. The fix will require careful
|
||||
consideration of the responsibilities of mail_addr_map(),
|
||||
mail_addr_find(), and mail_addr_crunch(), and making sure
|
||||
that the callers can handle quoted results. For example,
|
||||
sender_bcc_maps and recipient_bcc_maps invoke mail_addr_find()
|
||||
with unquoted forms and expects an unquoted result, and so on.
|
||||
|
||||
Maintainability: replace lengthy libmilter-API argument lists
|
||||
with named parameters, as with the libtls API.
|
||||
|
||||
|
@@ -46,127 +46,128 @@ POSTMAP(1) POSTMAP(1)
|
||||
|
||||
When the <i>key</i> specifies email address information, the localpart should
|
||||
be enclosed with double quotes if required by <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a>. For example, an
|
||||
address localpart that contains
|
||||
address localpart that contains ";", or a localpart that starts or ends
|
||||
with ".".
|
||||
|
||||
By default the lookup key is mapped to lowercase to make the lookups
|
||||
By default the lookup key is mapped to lowercase to make the lookups
|
||||
case insensitive; as of Postfix 2.3 this case folding happens only with
|
||||
tables whose lookup keys are fixed-case strings such as <a href="DATABASE_README.html#types">btree</a>:, <a href="DATABASE_README.html#types">dbm</a>: or
|
||||
<a href="DATABASE_README.html#types">hash</a>:. With earlier versions, the lookup key is folded even with tables
|
||||
where a lookup field can match both upper and lower case text, such as
|
||||
<a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in loss of information with $<i>number</i>
|
||||
where a lookup field can match both upper and lower case text, such as
|
||||
<a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in loss of information with $<i>number</i>
|
||||
substitutions.
|
||||
|
||||
<b>COMMAND-LINE ARGUMENTS</b>
|
||||
<b>-b</b> Enable message body query mode. When reading lookup keys from
|
||||
standard input with "<b>-q -</b>", process the input as if it is an
|
||||
email message in <a href="http://tools.ietf.org/html/rfc2822">RFC 2822</a> format. Each line of body content
|
||||
<b>-b</b> Enable message body query mode. When reading lookup keys from
|
||||
standard input with "<b>-q -</b>", process the input as if it is an
|
||||
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each line of body content
|
||||
becomes one lookup key.
|
||||
|
||||
By default, the <b>-b</b> option starts generating lookup keys at the
|
||||
first non-header line, and stops when the end of the message is
|
||||
reached. To simulate <a href="header_checks.5.html"><b>body_checks</b>(5)</a> processing, enable MIME
|
||||
parsing with <b>-m</b>. With this, the <b>-b</b> option generates no
|
||||
body-style lookup keys for attachment MIME headers and for
|
||||
By default, the <b>-b</b> option starts generating lookup keys at the
|
||||
first non-header line, and stops when the end of the message is
|
||||
reached. To simulate <a href="header_checks.5.html"><b>body_checks</b>(5)</a> processing, enable MIME
|
||||
parsing with <b>-m</b>. With this, the <b>-b</b> option generates no
|
||||
body-style lookup keys for attachment MIME headers and for
|
||||
attached message/* headers.
|
||||
|
||||
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
|
||||
ables UTF-8 syntax checks on query keys and lookup results.
|
||||
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
|
||||
ables UTF-8 syntax checks on query keys and lookup results.
|
||||
Specify the <b>-U</b> option to force UTF-8 syntax checks anyway.
|
||||
|
||||
This feature is available in Postfix version 2.6 and later.
|
||||
|
||||
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
|
||||
Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named directory
|
||||
Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named directory
|
||||
instead of the default configuration directory.
|
||||
|
||||
<b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one entry per map.
|
||||
The exit status is zero when the requested information was
|
||||
<b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one entry per map.
|
||||
The exit status is zero when the requested information was
|
||||
found.
|
||||
|
||||
If a key value of <b>-</b> is specified, the program reads key values
|
||||
from the standard input stream. The exit status is zero when at
|
||||
If a key value of <b>-</b> is specified, the program reads key values
|
||||
from the standard input stream. The exit status is zero when at
|
||||
least one of the requested keys was found.
|
||||
|
||||
<b>-f</b> Do not fold the lookup key to lower case while creating or
|
||||
<b>-f</b> Do not fold the lookup key to lower case while creating or
|
||||
querying a table.
|
||||
|
||||
With Postfix version 2.3 and later, this option has no effect
|
||||
With Postfix version 2.3 and later, this option has no effect
|
||||
for regular expression tables. There, case folding is controlled
|
||||
by appending a flag to a pattern.
|
||||
|
||||
<b>-h</b> Enable message header query mode. When reading lookup keys from
|
||||
standard input with "<b>-q -</b>", process the input as if it is an
|
||||
email message in <a href="http://tools.ietf.org/html/rfc2822">RFC 2822</a> format. Each logical header line
|
||||
becomes one lookup key. A multi-line header becomes one lookup
|
||||
<b>-h</b> Enable message header query mode. When reading lookup keys from
|
||||
standard input with "<b>-q -</b>", process the input as if it is an
|
||||
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each logical header line
|
||||
becomes one lookup key. A multi-line header becomes one lookup
|
||||
key with one or more embedded newline characters.
|
||||
|
||||
By default, the <b>-h</b> option generates lookup keys until the first
|
||||
non-header line is reached. To simulate <a href="header_checks.5.html"><b>header_checks</b>(5)</a> pro-
|
||||
cessing, enable MIME parsing with <b>-m</b>. With this, the <b>-h</b> option
|
||||
also generates header-style lookup keys for attachment MIME
|
||||
By default, the <b>-h</b> option generates lookup keys until the first
|
||||
non-header line is reached. To simulate <a href="header_checks.5.html"><b>header_checks</b>(5)</a> pro-
|
||||
cessing, enable MIME parsing with <b>-m</b>. With this, the <b>-h</b> option
|
||||
also generates header-style lookup keys for attachment MIME
|
||||
headers and for attached message/* headers.
|
||||
|
||||
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
|
||||
ables UTF-8 syntax checks on query keys and lookup results.
|
||||
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
|
||||
ables UTF-8 syntax checks on query keys and lookup results.
|
||||
Specify the <b>-U</b> option to force UTF-8 syntax checks anyway.
|
||||
|
||||
This feature is available in Postfix version 2.6 and later.
|
||||
|
||||
<b>-i</b> Incremental mode. Read entries from standard input and do not
|
||||
truncate an existing database. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> creates a
|
||||
<b>-i</b> Incremental mode. Read entries from standard input and do not
|
||||
truncate an existing database. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> creates a
|
||||
new database from the entries in <b>file_name</b>.
|
||||
|
||||
<b>-m</b> Enable MIME parsing with "<b>-b</b>" and "<b>-h</b>".
|
||||
|
||||
This feature is available in Postfix version 2.6 and later.
|
||||
|
||||
<b>-N</b> Include the terminating null character that terminates lookup
|
||||
keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is the
|
||||
<b>-N</b> Include the terminating null character that terminates lookup
|
||||
keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is the
|
||||
default for the host operating system.
|
||||
|
||||
<b>-n</b> Don't include the terminating null character that terminates
|
||||
lookup keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is
|
||||
<b>-n</b> Don't include the terminating null character that terminates
|
||||
lookup keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is
|
||||
the default for the host operating system.
|
||||
|
||||
<b>-o</b> Do not release root privileges when processing a non-root input
|
||||
file. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> drops root privileges and runs as
|
||||
<b>-o</b> Do not release root privileges when processing a non-root input
|
||||
file. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> drops root privileges and runs as
|
||||
the source file owner instead.
|
||||
|
||||
<b>-p</b> Do not inherit the file access permissions from the input file
|
||||
when creating a new file. Instead, create a new file with
|
||||
<b>-p</b> Do not inherit the file access permissions from the input file
|
||||
when creating a new file. Instead, create a new file with
|
||||
default access permissions (mode 0644).
|
||||
|
||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the first value
|
||||
found to the standard output stream. The exit status is zero
|
||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the first value
|
||||
found to the standard output stream. The exit status is zero
|
||||
when the requested information was found.
|
||||
|
||||
If a key value of <b>-</b> is specified, the program reads key values
|
||||
from the standard input stream and writes one line of <i>key value</i>
|
||||
If a key value of <b>-</b> is specified, the program reads key values
|
||||
from the standard input stream and writes one line of <i>key value</i>
|
||||
output for each key that was found. The exit status is zero when
|
||||
at least one of the requested keys was found.
|
||||
|
||||
<b>-r</b> When updating a table, do not complain about attempts to update
|
||||
<b>-r</b> When updating a table, do not complain about attempts to update
|
||||
existing entries, and make those updates anyway.
|
||||
|
||||
<b>-s</b> Retrieve all database elements, and write one line of <i>key value</i>
|
||||
output for each element. The elements are printed in database
|
||||
order, which is not necessarily the same as the original input
|
||||
<b>-s</b> Retrieve all database elements, and write one line of <i>key value</i>
|
||||
output for each element. The elements are printed in database
|
||||
order, which is not necessarily the same as the original input
|
||||
order.
|
||||
|
||||
This feature is available in Postfix version 2.2 and later, and
|
||||
This feature is available in Postfix version 2.2 and later, and
|
||||
is not available for all database types.
|
||||
|
||||
<b>-u</b> Disable UTF-8 support. UTF-8 support is enabled by default when
|
||||
"<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes". It requires that keys and values are
|
||||
<b>-u</b> Disable UTF-8 support. UTF-8 support is enabled by default when
|
||||
"<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes". It requires that keys and values are
|
||||
valid UTF-8 strings.
|
||||
|
||||
<b>-U</b> With "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", force UTF-8 syntax checks with the
|
||||
<b>-b</b> and <b>-h</b> options.
|
||||
|
||||
<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>-w</b> When updating a table, do not complain about attempts to update
|
||||
<b>-w</b> When updating a table, do not complain about attempts to update
|
||||
existing entries, and ignore those attempts.
|
||||
|
||||
Arguments:
|
||||
@@ -178,32 +179,32 @@ POSTMAP(1) POSTMAP(1)
|
||||
The <a href="postmap.1.html"><b>postmap</b>(1)</a> command can query any supported file type, but it
|
||||
can create only the following file types:
|
||||
|
||||
<b>btree</b> The output file is a btree file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
|
||||
This is available on systems with support for <b>db</b> data-
|
||||
<b>btree</b> The output file is a btree file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
|
||||
This is available on systems with support for <b>db</b> data-
|
||||
bases.
|
||||
|
||||
<b>cdb</b> The output consists of one file, named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
|
||||
This is available on systems with support for <b>cdb</b> data-
|
||||
<b>cdb</b> The output consists of one file, named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
|
||||
This is available on systems with support for <b>cdb</b> data-
|
||||
bases.
|
||||
|
||||
<b>dbm</b> The output consists of two files, named <i>file</i><b>_</b><i>name</i><b>.pag</b> and
|
||||
<i>file</i><b>_</b><i>name</i><b>.dir</b>. This is available on systems with support
|
||||
for <b>dbm</b> databases.
|
||||
|
||||
<b>hash</b> The output file is a hashed file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
|
||||
This is available on systems with support for <b>db</b> data-
|
||||
<b>hash</b> The output file is a hashed file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
|
||||
This is available on systems with support for <b>db</b> data-
|
||||
bases.
|
||||
|
||||
<b>fail</b> A table that reliably fails all requests. The lookup ta-
|
||||
ble name is used for logging only. This table exists to
|
||||
<b>fail</b> A table that reliably fails all requests. The lookup ta-
|
||||
ble name is used for logging only. This table exists to
|
||||
simplify Postfix error tests.
|
||||
|
||||
<b>sdbm</b> The output consists of two files, named <i>file</i><b>_</b><i>name</i><b>.pag</b> and
|
||||
<i>file</i><b>_</b><i>name</i><b>.dir</b>. This is available on systems with support
|
||||
for <b>sdbm</b> databases.
|
||||
|
||||
When no <i>file</i><b>_</b><i>type</i> is specified, the software uses the database
|
||||
type specified via the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
|
||||
When no <i>file</i><b>_</b><i>type</i> is specified, the software uses the database
|
||||
type specified via the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
|
||||
parameter.
|
||||
|
||||
<i>file</i><b>_</b><i>name</i>
|
||||
@@ -212,11 +213,11 @@ POSTMAP(1) POSTMAP(1)
|
||||
|
||||
<b>DIAGNOSTICS</b>
|
||||
Problems are logged to the standard error stream and to <b>syslogd</b>(8). No
|
||||
output means that no problems were detected. Duplicate entries are
|
||||
output means that no problems were detected. Duplicate entries are
|
||||
skipped and are flagged with a warning.
|
||||
|
||||
<a href="postmap.1.html"><b>postmap</b>(1)</a> terminates with zero exit status in case of success (includ-
|
||||
ing successful "<b>postmap -q</b>" lookup) and terminates with non-zero exit
|
||||
ing successful "<b>postmap -q</b>" lookup) and terminates with non-zero exit
|
||||
status in case of failure.
|
||||
|
||||
<b>ENVIRONMENT</b>
|
||||
@@ -227,12 +228,12 @@ POSTMAP(1) POSTMAP(1)
|
||||
Enable verbose logging for debugging purposes.
|
||||
|
||||
<b>CONFIGURATION PARAMETERS</b>
|
||||
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>post-</b></a>
|
||||
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>post-</b></a>
|
||||
<a href="postconf.5.html"><b>conf</b>(5)</a> for more details including examples.
|
||||
|
||||
<b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
|
||||
The per-table I/O buffer size for programs that create Berkeley
|
||||
The per-table I/O buffer size for programs that create Berkeley
|
||||
DB hash or btree tables.
|
||||
|
||||
<b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
|
||||
@@ -240,7 +241,7 @@ POSTMAP(1) POSTMAP(1)
|
||||
hash or btree tables.
|
||||
|
||||
<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#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
|
||||
@@ -248,14 +249,14 @@ POSTMAP(1) POSTMAP(1)
|
||||
and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
|
||||
|
||||
<b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
in <a href="http://tools.ietf.org/html/rfc6531">RFC 6531</a>..6533.
|
||||
|
||||
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
|
||||
The syslog facility of Postfix logging.
|
||||
|
||||
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
|
||||
A prefix that is prepended to the process name in syslog
|
||||
A prefix that is prepended to the process name in syslog
|
||||
records, so that, for example, "smtpd" becomes "prefix/smtpd".
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
|
@@ -56,7 +56,7 @@ keys is supported as of Postfix 3.2.
|
||||
When the \fIkey\fR specifies email address information, the
|
||||
localpart should be enclosed with double quotes if required
|
||||
by RFC 5322. For example, an address localpart that contains
|
||||
';' or that ends on '.'.
|
||||
";", or a localpart that starts or ends with ".".
|
||||
|
||||
By default the lookup key is mapped to lowercase to make
|
||||
the lookups case insensitive; as of Postfix 2.3 this case
|
||||
@@ -74,7 +74,7 @@ information with $\fInumber\fR substitutions.
|
||||
.IP \fB\-b\fR
|
||||
Enable message body query mode. When reading lookup keys
|
||||
from standard input with "\fB\-q \-\fR", process the input
|
||||
as if it is an email message in RFC 2822 format. Each line
|
||||
as if it is an email message in RFC 5322 format. Each line
|
||||
of body content becomes one lookup key.
|
||||
.sp
|
||||
By default, the \fB\-b\fR option starts generating lookup
|
||||
@@ -111,7 +111,7 @@ is controlled by appending a flag to a pattern.
|
||||
.IP \fB\-h\fR
|
||||
Enable message header query mode. When reading lookup keys
|
||||
from standard input with "\fB\-q \-\fR", process the input
|
||||
as if it is an email message in RFC 2822 format. Each
|
||||
as if it is an email message in RFC 5322 format. Each
|
||||
logical header line becomes one lookup key. A multi\-line
|
||||
header becomes one lookup key with one or more embedded
|
||||
newline characters.
|
||||
|
@@ -165,8 +165,9 @@ off_t cleanup_addr_sender(CLEANUP_STATE *state, const char *buf)
|
||||
if ((state->flags & CLEANUP_FLAG_BCC_OK)
|
||||
&& *STR(clean_addr)
|
||||
&& cleanup_send_bcc_maps) {
|
||||
if ((bcc = mail_addr_find(cleanup_send_bcc_maps, STR(clean_addr),
|
||||
IGNORE_EXTENSION)) != 0) {
|
||||
if ((bcc = mail_addr_find_to_internal(cleanup_send_bcc_maps,
|
||||
STR(clean_addr),
|
||||
IGNORE_EXTENSION)) != 0) {
|
||||
cleanup_addr_bcc(state, bcc);
|
||||
} else if (cleanup_send_bcc_maps->error) {
|
||||
msg_warn("%s: %s map lookup problem -- "
|
||||
@@ -228,8 +229,9 @@ void cleanup_addr_recipient(CLEANUP_STATE *state, const char *buf)
|
||||
if ((state->flags & CLEANUP_FLAG_BCC_OK)
|
||||
&& *STR(clean_addr)
|
||||
&& cleanup_rcpt_bcc_maps) {
|
||||
if ((bcc = mail_addr_find(cleanup_rcpt_bcc_maps, STR(clean_addr),
|
||||
IGNORE_EXTENSION)) != 0) {
|
||||
if ((bcc = mail_addr_find_to_internal(cleanup_rcpt_bcc_maps,
|
||||
STR(clean_addr),
|
||||
IGNORE_EXTENSION)) != 0) {
|
||||
cleanup_addr_bcc(state, bcc);
|
||||
} else if (cleanup_rcpt_bcc_maps->error) {
|
||||
msg_warn("%s: %s map lookup problem -- "
|
||||
|
@@ -105,6 +105,7 @@ int cleanup_map11_external(CLEANUP_STATE *state, VSTRING *addr,
|
||||
*/
|
||||
for (count = 0; count < MAX_RECURSION; count++) {
|
||||
if ((new_addr = mail_addr_map_opt(maps, STR(addr), propagate,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL)) != 0) {
|
||||
if (new_addr->argc > 1)
|
||||
|
@@ -118,7 +118,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
|
||||
valid_mailhost_addr own_inet_addr header_body_checks \
|
||||
data_redirect addr_match_list safe_ultostr verify_sender_addr \
|
||||
mail_version mail_dict server_acl uxtext mail_parm_split \
|
||||
fold_addr smtp_reply_footer mail_addr_map_tester
|
||||
fold_addr smtp_reply_footer mail_addr_map
|
||||
|
||||
LIBS = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
|
||||
LIB_DIR = ../../lib
|
||||
@@ -249,8 +249,10 @@ off_cvt: $(LIB) $(LIBS)
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
mail_addr_map_tester: mail_addr_map_tester.c $(LIB) $(LIBS)
|
||||
mail_addr_map: mail_addr_map.c $(LIB) $(LIBS)
|
||||
mv $@.o junk
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
mail_addr_find: $(LIB) $(LIBS)
|
||||
mv $@.o junk
|
||||
@@ -683,9 +685,9 @@ mail_addr_find_test: update mail_addr_find mail_addr_find.in mail_addr_find.ref
|
||||
diff mail_addr_find.ref mail_addr_find.tmp
|
||||
rm -f mail_addr_find.tmp
|
||||
|
||||
mail_addr_map_test: update mail_addr_map_tester mail_addr_map.ref
|
||||
-$(SHLIB_ENV) $(VALGRIND) ./mail_addr_map_tester pass_tests
|
||||
-$(SHLIB_ENV) $(VALGRIND) ./mail_addr_map_tester fail_tests >mail_addr_map.tmp 2>&1
|
||||
mail_addr_map_test: update mail_addr_map mail_addr_map.ref
|
||||
-$(SHLIB_ENV) $(VALGRIND) ./mail_addr_map pass_tests
|
||||
-$(SHLIB_ENV) $(VALGRIND) ./mail_addr_map fail_tests >mail_addr_map.tmp 2>&1
|
||||
diff mail_addr_map.ref mail_addr_map.tmp
|
||||
rm -f mail_addr_map.tmp
|
||||
|
||||
@@ -1490,6 +1492,7 @@ mail_addr_find.o: ../../include/dict.h
|
||||
mail_addr_find.o: ../../include/msg.h
|
||||
mail_addr_find.o: ../../include/myflock.h
|
||||
mail_addr_find.o: ../../include/mymalloc.h
|
||||
mail_addr_find.o: ../../include/name_mask.h
|
||||
mail_addr_find.o: ../../include/stringops.h
|
||||
mail_addr_find.o: ../../include/sys_defs.h
|
||||
mail_addr_find.o: ../../include/vbuf.h
|
||||
@@ -1526,23 +1529,6 @@ mail_addr_map.o: mail_addr_map.h
|
||||
mail_addr_map.o: maps.h
|
||||
mail_addr_map.o: quote_822_local.h
|
||||
mail_addr_map.o: quote_flags.h
|
||||
mail_addr_map_tester.o: ../../include/argv.h
|
||||
mail_addr_map_tester.o: ../../include/check_arg.h
|
||||
mail_addr_map_tester.o: ../../include/dict.h
|
||||
mail_addr_map_tester.o: ../../include/msg.h
|
||||
mail_addr_map_tester.o: ../../include/myflock.h
|
||||
mail_addr_map_tester.o: ../../include/mymalloc.h
|
||||
mail_addr_map_tester.o: ../../include/sys_defs.h
|
||||
mail_addr_map_tester.o: ../../include/vbuf.h
|
||||
mail_addr_map_tester.o: ../../include/vstream.h
|
||||
mail_addr_map_tester.o: ../../include/vstring.h
|
||||
mail_addr_map_tester.o: canon_addr.h
|
||||
mail_addr_map_tester.o: mail_addr_form.h
|
||||
mail_addr_map_tester.o: mail_addr_map.h
|
||||
mail_addr_map_tester.o: mail_addr_map_tester.c
|
||||
mail_addr_map_tester.o: mail_conf.h
|
||||
mail_addr_map_tester.o: mail_params.h
|
||||
mail_addr_map_tester.o: maps.h
|
||||
mail_command_client.o: ../../include/attr.h
|
||||
mail_command_client.o: ../../include/check_arg.h
|
||||
mail_command_client.o: ../../include/htable.h
|
||||
|
@@ -11,12 +11,13 @@
|
||||
/* const char *address;
|
||||
/* char **extension;
|
||||
/*
|
||||
/* const char *mail_addr_find_opt(maps, address, extension,
|
||||
/* in_form, out_form, strategy)
|
||||
/* const char *mail_addr_find_opt(maps, address, extension, in_form,
|
||||
/* query_form, out_form, strategy)
|
||||
/* MAPS *maps;
|
||||
/* const char *address;
|
||||
/* char **extension;
|
||||
/* int in_form;
|
||||
/* int in_form;
|
||||
/* int out_form;
|
||||
/* int strategy;
|
||||
/* LEGACY SUPPORT
|
||||
@@ -25,6 +26,11 @@
|
||||
/* const char *address;
|
||||
/* char **extension;
|
||||
/*
|
||||
/* const char *mail_addr_find_to_internal(maps, address, extension)
|
||||
/* MAPS *maps;
|
||||
/* const char *address;
|
||||
/* char **extension;
|
||||
/*
|
||||
/* const char *mail_addr_find_strategy(maps, address, extension)
|
||||
/* MAPS *maps;
|
||||
/* const char *address;
|
||||
@@ -37,33 +43,37 @@
|
||||
/* preferences when it opens the maps.
|
||||
/* The result is overwritten upon each call.
|
||||
/*
|
||||
/* The table key and value are expected to be in external
|
||||
/* (quoted) form. Override these assumptions with the in_form
|
||||
/* In the lookup table, the key is expected to be in external
|
||||
/* form (as produced with the postmap command) and the value is
|
||||
/* expected to be in external (quoted) form if it is an email
|
||||
/* address. Override these assumptions with the query_form
|
||||
/* and out_form arguments.
|
||||
/*
|
||||
/* With mail_addr_find_int_to_ext(), the specified address is in
|
||||
/* internal (unquoted) form. The result is in the form found
|
||||
/* in the table (it is not necessarily an email address). This
|
||||
/* version minimizes internal/external (unquoted/quoted)
|
||||
/* conversions of the query, extension, or result.
|
||||
/* internal (unquoted) form, the query is made in external (quoted)
|
||||
/* form, and the result is in the form found in the table (it is
|
||||
/* not necessarily an email address). This version minimizes
|
||||
/* internal/external (unquoted/quoted) conversions of the input,
|
||||
/* query, extension, or result.
|
||||
/*
|
||||
/* mail_addr_find_opt() gives more control, at the cost of
|
||||
/* additional conversions between internal and external forms.
|
||||
/* In particular, the output conversion to internal form assumes
|
||||
/* In particular, output conversion to internal form assumes
|
||||
/* that the lookup result is an email address.
|
||||
/*
|
||||
/* mail_addr_find() is used by legacy code that historically
|
||||
/* searched with internal-form keys. The lookup strategy is
|
||||
/* to first look up with (in_form, out_form) of (INTERNAL,
|
||||
/* NOCONV), which converts the key to external form. If no
|
||||
/* result is found, and the internal and external key forms
|
||||
/* differ, there is a backwards-compatibility lookup with
|
||||
/* (in_form, out_form) of (NOCONV, NOCONV).
|
||||
/* mail_addr_find() is used by legacy code that historically searched
|
||||
/* with internal-form queries. The input is in internal form. It
|
||||
/* searches with external-form queries first, and falls back to
|
||||
/* internal-form queries if no result was found and the external
|
||||
/* and internal forms differ. The result is external form (i.e. no
|
||||
/* conversion).
|
||||
/*
|
||||
/* mail_addr_find_strategy() overrides the default search
|
||||
/* strategy for full and partial addresses.
|
||||
/* mail_addr_find_to_internal() is like mail_addr_find() but assumes
|
||||
/* that the lookup result is one external-form email address,
|
||||
/* and converts it to internal form.
|
||||
/*
|
||||
/* An address that is in the form \fIuser\fR matches itself.
|
||||
/* mail_addr_find_strategy() is like mail_addr_find() but overrides
|
||||
/* the default search strategy for full and partial addresses.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP maps
|
||||
@@ -77,48 +87,54 @@
|
||||
/* The copy includes the recipient address delimiter.
|
||||
/* The copy is in internal (unquoted) form.
|
||||
/* The caller is expected to pass the copy to myfree().
|
||||
/* .IP query_form
|
||||
/* The address form to use for database queries: one of
|
||||
/* MAIL_ADDR_FORM_INTERNAL (unquoted form), MAIL_ADDR_FORM_EXTERNAL
|
||||
/* (quoted form), or MAIL_ADDR_FORM_EXTERNAL_FIRST (external form,
|
||||
/* then internal form if the external and internal forms differ).
|
||||
/* .IP in_form
|
||||
/* .IP out_form
|
||||
/* Input and output address forms, either MAIL_ADDR_FORM_INTERNAL
|
||||
/* (unquoted form), MAIL_ADDR_FORM_EXTERNAL (quoted form), or
|
||||
/* MAIL_ADDR_FORM_NOCONV (don't convert between unquoted and
|
||||
/* quoted form).
|
||||
/* Input and output address forms, one of MAIL_ADDR_FORM_INTERNAL
|
||||
/* (unquoted form), or MAIL_ADDR_FORM_EXTERNAL (quoted form).
|
||||
/* .IP strategy
|
||||
/* The lookup strategy for full and partial addresses, specified
|
||||
/* as the binary OR of one or more of the following. These
|
||||
/* lookups are implemented in the order as listed below.
|
||||
/* as the binary OR of one or more of the following. These lookups
|
||||
/* are implemented in the order as listed below.
|
||||
/* .RS
|
||||
/* .IP MAIL_ADDR_FIND_FULL
|
||||
/* .IP MAF_STRATEGY_DEFAULT
|
||||
/* A convenience alias for (MAF_STRATEGY_FULL | MAF_STRATEGY_NOEXT |
|
||||
/* MAF_STRATEGY_LOCALPART_IF_LOCAL | MAF_STRATEGY_AT_DOMAIN).
|
||||
/* .IP MAF_STRATEGY_FULL
|
||||
/* Look up the full email address.
|
||||
/* .IP MAIL_ADDR_FIND_NOEXT
|
||||
/* If no match was found, and the address has an extension,
|
||||
/* look up the address after removing the address extension.
|
||||
/* .IP MAIL_ADDR_FIND_LOCALPART_IF_LOCAL
|
||||
/* .IP MAF_STRATEGY_NOEXT
|
||||
/* If no match was found, and the address has a localpart extension,
|
||||
/* look up the address after removing the extension.
|
||||
/* .IP MAF_STRATEGY_LOCALPART_IF_LOCAL
|
||||
/* If no match was found, and the domain matches myorigin,
|
||||
/* mydestination, or any proxy_interfaces IP address, look up
|
||||
/* the localpart. If no match was found, and the address has
|
||||
/* an extension, repeat the same query after removing the
|
||||
/* address extension unless MAIL_ADDR_FIND_NOEXT is specified.
|
||||
/* .IP MAIL_ADDR_FIND_LOCALPART_AT_IF_LOCAL
|
||||
/* mydestination, or any inet_interfaces or proxy_interfaces IP
|
||||
/* address, look up the localpart. If no match was found, and the
|
||||
/* address has a localpart extension, repeat the same query after
|
||||
/* removing the extension unless MAF_STRATEGY_NOEXT is specified.
|
||||
/* .IP MAF_STRATEGY_LOCALPART_AT_IF_LOCAL
|
||||
/* As above, but using the localpart@ instead.
|
||||
/* .IP MAIL_ADDR_FIND_ATDOMAIN
|
||||
/* .IP MAF_STRATEGY_AT_DOMAIN
|
||||
/* If no match was found, look up the @domain without localpart.
|
||||
/* .IP MAIL_ADDR_FIND_DOMAIN
|
||||
/* .IP MAF_STRATEGY_DOMAIN
|
||||
/* If no match was found, look up the domain without localpart.
|
||||
/* .IP MAIL_ADDR_FIND_PMS
|
||||
/* When used with MAIL_ADDR_FIND_DOMAIN, also matches subdomains.
|
||||
/* .IP MAIL_ADDR_FIND_PMDS
|
||||
/* When used with MAIL_ADDR_FIND_DOMAIN, also matches dot-subdomains.
|
||||
/* .IP MAIL_ADDR_FIND_LOCALPART_AT
|
||||
/* If no match was found, look up the localpart@, regardless
|
||||
/* of the domain content.
|
||||
/* .IP MAF_STRATEGY_PMS
|
||||
/* When used with MAF_STRATEGY_DOMAIN, also matches subdomains.
|
||||
/* .IP MAF_STRATEGY_PMDS
|
||||
/* When used with MAF_STRATEGY_DOMAIN, also matches dot-subdomains.
|
||||
/* .IP MAF_STRATEGY_LOCALPART_AT
|
||||
/* If no match was found, look up the localpart@, regardless of
|
||||
/* the domain content.
|
||||
/* .RE
|
||||
/* DIAGNOSTICS
|
||||
/* The maps->error value is non-zero when the lookup
|
||||
/* should be tried again.
|
||||
/* The maps->error value is non-zero when the lookup should be
|
||||
/* tried again.
|
||||
/* SEE ALSO
|
||||
/* maps(3), multi-dictionary search
|
||||
/* resolve_local(3), recognize local system
|
||||
/* maps(3), multi-dictionary search resolve_local(3), recognize
|
||||
/* local system
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@@ -156,27 +172,22 @@
|
||||
|
||||
#define STR vstring_str
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
static const NAME_MASK strategy_table[] = {
|
||||
"full", MAIL_ADDR_FIND_FULL,
|
||||
"noext", MAIL_ADDR_FIND_NOEXT,
|
||||
"localpart_if_local", MAIL_ADDR_FIND_LOCALPART_IF_LOCAL,
|
||||
"localpart_at_if_local", MAIL_ADDR_FIND_LOCALPART_AT_IF_LOCAL,
|
||||
"atdomain", MAIL_ADDR_FIND_ATDOMAIN,
|
||||
"domain", MAIL_ADDR_FIND_DOMAIN,
|
||||
"pms", MAIL_ADDR_FIND_PMS,
|
||||
"pmds", MAIL_ADDR_FIND_PMDS,
|
||||
"localpartat", MAIL_ADDR_FIND_LOCALPART_AT,
|
||||
"default", MAIL_ADDR_FIND_DEFAULT,
|
||||
"full", MAF_STRATEGY_FULL,
|
||||
"noext", MAF_STRATEGY_NOEXT,
|
||||
"localpart_if_local", MAF_STRATEGY_LOCALPART_IF_LOCAL,
|
||||
"localpart_at_if_local", MAF_STRATEGY_LOCALPART_AT_IF_LOCAL,
|
||||
"atdomain", MAF_STRATEGY_AT_DOMAIN,
|
||||
"domain", MAF_STRATEGY_DOMAIN,
|
||||
"pms", MAF_STRATEGY_PMS,
|
||||
"pmds", MAF_STRATEGY_PMDS,
|
||||
"localpart_at", MAF_STRATEGY_LOCALPART_AT,
|
||||
"default", MAF_STRATEGY_DEFAULT,
|
||||
0, -1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Specify what keys are partial or full, to avoid matching partial
|
||||
* addresses with regular expressions.
|
||||
*/
|
||||
#define FULL 0
|
||||
#define PARTIAL DICT_FLAG_FIXED
|
||||
|
||||
/* strategy_from_string - symbolic strategy flags to internal form */
|
||||
|
||||
static int strategy_from_string(const char *strategy_string)
|
||||
@@ -199,29 +210,63 @@ static const char *strategy_to_string(VSTRING *res_buf, int strategy_mask)
|
||||
NAME_MASK_WARN | NAME_MASK_PIPE));
|
||||
}
|
||||
|
||||
/* find_addr - helper to search map with external-form address */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Specify what keys are partial or full, to avoid matching partial
|
||||
* addresses with regular expressions.
|
||||
*/
|
||||
#define FULL 0
|
||||
#define PARTIAL DICT_FLAG_FIXED
|
||||
|
||||
/* find_addr - helper to search maps with the right query form */
|
||||
|
||||
static const char *find_addr(MAPS *path, const char *address, int flags,
|
||||
int with_domain, int find_form, VSTRING *ext_addr_buf)
|
||||
int with_domain, int query_form, VSTRING *ext_addr_buf)
|
||||
{
|
||||
const char *result;
|
||||
|
||||
#define SANS_DOMAIN 0
|
||||
#define WITH_DOMAIN 1
|
||||
|
||||
if (find_form == MAIL_ADDR_FORM_INTERNAL) {
|
||||
switch (query_form) {
|
||||
|
||||
/*
|
||||
* Query with external-form (quoted) address.
|
||||
*/
|
||||
case MAIL_ADDR_FORM_EXTERNAL:
|
||||
case MAIL_ADDR_FORM_EXTERNAL_FIRST:
|
||||
quote_822_local_flags(ext_addr_buf, address,
|
||||
with_domain ? QUOTE_FLAG_DEFAULT :
|
||||
QUOTE_FLAG_DEFAULT | QUOTE_FLAG_BARE_LOCALPART);
|
||||
address = STR(ext_addr_buf);
|
||||
result = maps_find(path, STR(ext_addr_buf), flags);
|
||||
if (result != 0 || path->error != 0
|
||||
|| query_form == MAIL_ADDR_FORM_EXTERNAL
|
||||
|| strcmp(address, STR(ext_addr_buf)) == 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
/*
|
||||
* Query with internal-form (unquoted) address.
|
||||
*/
|
||||
case MAIL_ADDR_FORM_INTERNAL:
|
||||
result = maps_find(path, address, flags);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Can't happen.
|
||||
*/
|
||||
default:
|
||||
msg_panic("mail_addr_find: bad query_form: %d", query_form);
|
||||
}
|
||||
return (maps_find(path, address, flags));
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* find_local - search on localpart info */
|
||||
|
||||
static const char *find_local(MAPS *path, char *ratsign, int rats_offs,
|
||||
char *int_full_key, char *int_bare_key,
|
||||
int find_form, char **extp, char **saved_ext,
|
||||
int query_form, char **extp, char **saved_ext,
|
||||
VSTRING *ext_addr_buf)
|
||||
{
|
||||
const char *myname = "mail_addr_find";
|
||||
@@ -230,15 +275,15 @@ static const char *find_local(MAPS *path, char *ratsign, int rats_offs,
|
||||
int saved_ch;
|
||||
|
||||
/*
|
||||
* This was ripped from the middle of a function so it can be reused,
|
||||
* that's why the interface makes no sense.
|
||||
* This code was ripped from the middle of a function so that it can be
|
||||
* reused multiple times, that's why the interface makes little sense.
|
||||
*/
|
||||
with_domain = rats_offs ? WITH_DOMAIN : SANS_DOMAIN;
|
||||
|
||||
saved_ch = *(unsigned char *) (ratsign + rats_offs);
|
||||
*(ratsign + rats_offs) = 0;
|
||||
result = find_addr(path, int_full_key, PARTIAL, with_domain,
|
||||
find_form, ext_addr_buf);
|
||||
query_form, ext_addr_buf);
|
||||
*(ratsign + rats_offs) = saved_ch;
|
||||
if (result == 0 && path->error == 0 && int_bare_key != 0) {
|
||||
if ((ratsign = strrchr(int_bare_key, '@')) == 0)
|
||||
@@ -246,7 +291,7 @@ static const char *find_local(MAPS *path, char *ratsign, int rats_offs,
|
||||
saved_ch = *(unsigned char *) (ratsign + rats_offs);
|
||||
*(ratsign + rats_offs) = 0;
|
||||
if ((result = find_addr(path, int_bare_key, PARTIAL, with_domain,
|
||||
find_form, ext_addr_buf)) != 0
|
||||
query_form, ext_addr_buf)) != 0
|
||||
&& extp != 0) {
|
||||
*extp = *saved_ext;
|
||||
*saved_ext = 0;
|
||||
@@ -259,11 +304,11 @@ static const char *find_local(MAPS *path, char *ratsign, int rats_offs,
|
||||
/* mail_addr_find_opt - map a canonical address */
|
||||
|
||||
const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
int in_form, int out_form, int strategy)
|
||||
int in_form, int query_form,
|
||||
int out_form, int strategy)
|
||||
{
|
||||
const char *myname = "mail_addr_find";
|
||||
VSTRING *ext_addr_buf = 0;
|
||||
int find_form;
|
||||
VSTRING *int_addr_buf = 0;
|
||||
const char *int_addr;
|
||||
static VSTRING *int_result = 0;
|
||||
@@ -275,27 +320,27 @@ const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* Optionally convert input from external form.
|
||||
* Optionally convert the address from external form.
|
||||
*/
|
||||
if (in_form == MAIL_ADDR_FORM_EXTERNAL) {
|
||||
int_addr_buf = vstring_alloc(100);
|
||||
unquote_822_local(int_addr_buf, address);
|
||||
int_addr = STR(int_addr_buf);
|
||||
find_form = MAIL_ADDR_FORM_INTERNAL;
|
||||
} else {
|
||||
int_addr = address;
|
||||
find_form = in_form;
|
||||
}
|
||||
if (find_form == MAIL_ADDR_FORM_INTERNAL)
|
||||
if (query_form == MAIL_ADDR_FORM_EXTERNAL_FIRST
|
||||
|| query_form == MAIL_ADDR_FORM_EXTERNAL)
|
||||
ext_addr_buf = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
int_full_key = mystrdup(int_addr);
|
||||
if (*var_rcpt_delim == 0 || (strategy & MAIL_ADDR_FIND_NOEXT) == 0) {
|
||||
if (*var_rcpt_delim == 0 || (strategy & MAF_STRATEGY_NOEXT) == 0) {
|
||||
int_bare_key = saved_ext = 0;
|
||||
} else {
|
||||
/* XXX This could be done after user+foo@domain fails. */
|
||||
int_bare_key =
|
||||
strip_addr_internal(int_full_key, &saved_ext, var_rcpt_delim);
|
||||
}
|
||||
@@ -303,9 +348,9 @@ const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
/*
|
||||
* Try user+foo@domain and user@domain.
|
||||
*/
|
||||
if ((strategy & MAIL_ADDR_FIND_FULL) != 0) {
|
||||
if ((strategy & MAF_STRATEGY_FULL) != 0) {
|
||||
result = find_addr(path, int_full_key, FULL, WITH_DOMAIN,
|
||||
find_form, ext_addr_buf);
|
||||
query_form, ext_addr_buf);
|
||||
} else {
|
||||
result = 0;
|
||||
path->error = 0;
|
||||
@@ -313,31 +358,31 @@ const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
|
||||
if (result == 0 && path->error == 0 && int_bare_key != 0
|
||||
&& (result = find_addr(path, int_bare_key, PARTIAL, WITH_DOMAIN,
|
||||
find_form, ext_addr_buf)) != 0
|
||||
query_form, ext_addr_buf)) != 0
|
||||
&& extp != 0) {
|
||||
*extp = saved_ext;
|
||||
saved_ext = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try user+foo, if the domain matches user+foo@$myorigin,
|
||||
* Try user+foo if the domain matches user+foo@$myorigin,
|
||||
* user+foo@$mydestination or user+foo@[${proxy,inet}_interfaces]. Then
|
||||
* try with +foo stripped off.
|
||||
*/
|
||||
if (result == 0 && path->error == 0
|
||||
&& (ratsign = strrchr(int_full_key, '@')) != 0
|
||||
&& (strategy & (MAIL_ADDR_FIND_LOCALPART_IF_LOCAL
|
||||
| MAIL_ADDR_FIND_LOCALPART_AT_IF_LOCAL)) != 0) {
|
||||
&& (strategy & (MAF_STRATEGY_LOCALPART_IF_LOCAL
|
||||
| MAF_STRATEGY_LOCALPART_AT_IF_LOCAL)) != 0) {
|
||||
if (strcasecmp_utf8(ratsign + 1, var_myorigin) == 0
|
||||
|| (rc = resolve_local(ratsign + 1)) > 0) {
|
||||
if ((strategy & MAIL_ADDR_FIND_LOCALPART_IF_LOCAL) != 0)
|
||||
if ((strategy & MAF_STRATEGY_LOCALPART_IF_LOCAL) != 0)
|
||||
result = find_local(path, ratsign, 0, int_full_key,
|
||||
int_bare_key, find_form, extp, &saved_ext,
|
||||
int_bare_key, query_form, extp, &saved_ext,
|
||||
ext_addr_buf);
|
||||
if (result == 0 && path->error == 0
|
||||
&& (strategy & MAIL_ADDR_FIND_LOCALPART_AT_IF_LOCAL) != 0)
|
||||
&& (strategy & MAF_STRATEGY_LOCALPART_AT_IF_LOCAL) != 0)
|
||||
result = find_local(path, ratsign, 1, int_full_key,
|
||||
int_bare_key, find_form, extp, &saved_ext,
|
||||
int_bare_key, query_form, extp, &saved_ext,
|
||||
ext_addr_buf);
|
||||
} else if (rc < 0)
|
||||
path->error = rc;
|
||||
@@ -347,40 +392,40 @@ const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
* Try @domain.
|
||||
*/
|
||||
if (result == 0 && path->error == 0 && ratsign != 0
|
||||
&& (strategy & MAIL_ADDR_FIND_ATDOMAIN) != 0)
|
||||
&& (strategy & MAF_STRATEGY_AT_DOMAIN) != 0)
|
||||
result = maps_find(path, ratsign, PARTIAL);
|
||||
|
||||
/*
|
||||
* Try domain (optionally, subdomains).
|
||||
*/
|
||||
if (result == 0 && path->error == 0 && ratsign != 0
|
||||
&& (strategy & MAIL_ADDR_FIND_DOMAIN) != 0) {
|
||||
&& (strategy & MAF_STRATEGY_DOMAIN) != 0) {
|
||||
const char *name;
|
||||
const char *next;
|
||||
|
||||
for (name = ratsign + 1; *name != 0; name = next) {
|
||||
if ((result = maps_find(path, name, PARTIAL)) != 0
|
||||
|| path->error != 0
|
||||
|| (strategy & (MAIL_ADDR_FIND_PMS | MAIL_ADDR_FIND_PMDS)) == 0
|
||||
|| (strategy & (MAF_STRATEGY_PMS | MAF_STRATEGY_PMDS)) == 0
|
||||
|| (next = strchr(name + 1, '.')) == 0)
|
||||
break;
|
||||
if ((strategy & MAIL_ADDR_FIND_PMDS) == 0)
|
||||
if ((strategy & MAF_STRATEGY_PMDS) == 0)
|
||||
next++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try localpart@ even if not local.
|
||||
* Try localpart@ even if the domain is not local.
|
||||
*/
|
||||
if ((strategy & MAIL_ADDR_FIND_LOCALPART_AT) != 0 \
|
||||
if ((strategy & MAF_STRATEGY_LOCALPART_AT) != 0 \
|
||||
&&result == 0 && path->error == 0)
|
||||
result = find_local(path, ratsign, 1, int_full_key,
|
||||
int_bare_key, find_form, extp, &saved_ext,
|
||||
int_bare_key, query_form, extp, &saved_ext,
|
||||
ext_addr_buf);
|
||||
|
||||
/*
|
||||
* Optionally convert the result to internal form. The lookup result is
|
||||
* supposed to be in external form.
|
||||
* supposed to be one external-form email address.
|
||||
*/
|
||||
if (result != 0 && out_form == MAIL_ADDR_FORM_INTERNAL) {
|
||||
if (int_result == 0)
|
||||
@@ -409,40 +454,6 @@ const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* mail_addr_find_strategy - map a canonical address */
|
||||
|
||||
const char *mail_addr_find_strategy(MAPS *path, const char *address,
|
||||
char **extp, int strategy)
|
||||
{
|
||||
static VSTRING *ext_addr_buf;
|
||||
const char *result;
|
||||
|
||||
/*
|
||||
* The future: look up with MAIL_ADDR_FORM_INTERNAL, which converts keys
|
||||
* to external form.
|
||||
*/
|
||||
if ((result = mail_addr_find_opt(path, address, extp,
|
||||
MAIL_ADDR_FORM_INTERNAL,
|
||||
MAIL_ADDR_FORM_NOCONV,
|
||||
strategy)) != 0
|
||||
|| path->error != 0)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* The past: look up with MAIL_ADDR_FORM_NOCONV, which leaves keys in
|
||||
* internal form.
|
||||
*/
|
||||
if (ext_addr_buf == 0)
|
||||
ext_addr_buf = vstring_alloc(100);
|
||||
quote_822_local(ext_addr_buf, address);
|
||||
if (strcmp(STR(ext_addr_buf), address) != 0)
|
||||
result = mail_addr_find_opt(path, address, extp,
|
||||
MAIL_ADDR_FORM_NOCONV,
|
||||
MAIL_ADDR_FORM_NOCONV,
|
||||
strategy);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
@@ -455,23 +466,25 @@ const char *mail_addr_find_strategy(MAPS *path, const char *address,
|
||||
|
||||
static NORETURN usage(const char *progname)
|
||||
{
|
||||
msg_fatal("usage: %s [-v] database", progname);
|
||||
msg_fatal("usage: %s [-v]", progname);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
VSTRING *buffer = vstring_alloc(100);
|
||||
char *bp;
|
||||
MAPS *path;
|
||||
MAPS *path = 0;
|
||||
const char *result;
|
||||
char *extent;
|
||||
char *in_field;
|
||||
char *query_field;
|
||||
char *out_field;
|
||||
char *strategy_field;
|
||||
char *key_field;
|
||||
char *expect_res;
|
||||
char *expect_ext;
|
||||
int in_form;
|
||||
int query_form;
|
||||
int out_form;
|
||||
int strategy_flags;
|
||||
int ch;
|
||||
@@ -489,7 +502,7 @@ int main(int argc, char **argv)
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc != optind + 1)
|
||||
if (argc != optind)
|
||||
usage(argv[0]);
|
||||
|
||||
/*
|
||||
@@ -502,26 +515,38 @@ int main(int argc, char **argv)
|
||||
UPDATE(var_mydomain, "localdomain");
|
||||
UPDATE(var_myorigin, "localdomain");
|
||||
UPDATE(var_mydest, "localhost.localdomain");
|
||||
path = maps_create(argv[0], argv[optind], DICT_FLAG_LOCK
|
||||
| DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
|
||||
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
|
||||
bp = STR(buffer);
|
||||
if (msg_verbose)
|
||||
msg_info("> %s", bp);
|
||||
|
||||
/*
|
||||
* Quick and dirty.
|
||||
*/
|
||||
if (path == 0) {
|
||||
path = maps_create(argv[0], bp, DICT_FLAG_LOCK
|
||||
| DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
|
||||
vstream_printf("%s\n", bp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the input and expectations.
|
||||
*/
|
||||
/* internal, external, noconv, or compat. */
|
||||
/* internal, external. */
|
||||
if ((in_field = mystrtok(&bp, ":")) == 0)
|
||||
msg_fatal("no input form");
|
||||
if ((in_form = mail_addr_form_from_string(in_field)) < 0
|
||||
&& strcmp(in_field, "compat") != 0)
|
||||
if ((in_form = mail_addr_form_from_string(in_field)) < 0)
|
||||
msg_fatal("bad input form: '%s'", in_field);
|
||||
if ((query_field = mystrtok(&bp, ":")) == 0)
|
||||
msg_fatal("no query form");
|
||||
/* internal, external, external-first. */
|
||||
if ((query_form = mail_addr_form_from_string(query_field)) < 0)
|
||||
msg_fatal("bad query form: '%s'", query_field);
|
||||
if ((out_field = mystrtok(&bp, ":")) == 0)
|
||||
msg_fatal("no output form");
|
||||
/* internal, external, noconv, or compat, depending on in_form. */
|
||||
if (((out_form = mail_addr_form_from_string(out_field)) < 0
|
||||
&& strcmp(out_field, "compat") != 0)
|
||||
|| ((in_form >= 0) != (out_form >= 0)))
|
||||
/* internal, external. */
|
||||
if ((out_form = mail_addr_form_from_string(out_field)) < 0)
|
||||
msg_fatal("bad output form: '%s'", out_field);
|
||||
if ((strategy_field = mystrtok(&bp, ":")) == 0)
|
||||
msg_fatal("no strategy field");
|
||||
@@ -538,18 +563,11 @@ int main(int argc, char **argv)
|
||||
* Lookups.
|
||||
*/
|
||||
extent = 0;
|
||||
if (in_form >= 0 && out_form >= 0) {
|
||||
/* It's the future. */
|
||||
result = mail_addr_find_opt(path, key_field, &extent,
|
||||
in_form, out_form,
|
||||
strategy_flags);
|
||||
} else {
|
||||
/* Backwards compatibility. */
|
||||
result = mail_addr_find_strategy(path, key_field, &extent,
|
||||
strategy_flags);
|
||||
}
|
||||
vstream_printf("%s:%s -> %s:%s (%s)\n",
|
||||
in_field, key_field, out_field, result ? result :
|
||||
result = mail_addr_find_opt(path, key_field, &extent,
|
||||
in_form, query_form, out_form,
|
||||
strategy_flags);
|
||||
vstream_printf("%s:%s -%s-> %s:%s (%s)\n",
|
||||
in_field, key_field, query_field, out_field, result ? result :
|
||||
path->error ? "(try again)" :
|
||||
"(not found)", extent ? extent : "null extension");
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef _MAIL_ADDR_FIND_H_INCLUDED_
|
||||
#define _MAIL_ADDR_FIND_H_INCLUDED_
|
||||
#ifndef _MAF_STRATEGY_H_INCLUDED_
|
||||
#define _MAF_STRATEGY_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
@@ -20,38 +20,48 @@
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern const char *mail_addr_find_opt(MAPS *, const char *, char **,
|
||||
int, int, int);
|
||||
extern const char *mail_addr_find_opt(MAPS *, const char *, char **,
|
||||
int, int, int, int);
|
||||
|
||||
#define MAIL_ADDR_FIND_FULL (1<<0) /* localpart+ext@domain */
|
||||
#define MAIL_ADDR_FIND_NOEXT (1<<1) /* localpart@domain */
|
||||
#define MAIL_ADDR_FIND_LOCALPART_IF_LOCAL \
|
||||
#define MAF_STRATEGY_FULL (1<<0) /* localpart+ext@domain */
|
||||
#define MAF_STRATEGY_NOEXT (1<<1) /* localpart@domain */
|
||||
#define MAF_STRATEGY_LOCALPART_IF_LOCAL \
|
||||
(1<<2) /* localpart (maybe localpart+ext) */
|
||||
#define MAIL_ADDR_FIND_LOCALPART_AT_IF_LOCAL \
|
||||
#define MAF_STRATEGY_LOCALPART_AT_IF_LOCAL \
|
||||
(1<<3) /* ditto, with @ at end */
|
||||
#define MAIL_ADDR_FIND_ATDOMAIN (1<<4) /* @domain */
|
||||
#define MAIL_ADDR_FIND_DOMAIN (1<<5) /* domain */
|
||||
#define MAIL_ADDR_FIND_PMS (1<<6) /* parent matches subdomain */
|
||||
#define MAIL_ADDR_FIND_PMDS (1<<7) /* parent matches dot-subdomain */
|
||||
#define MAIL_ADDR_FIND_LOCALPART_AT \
|
||||
#define MAF_STRATEGY_AT_DOMAIN (1<<4) /* @domain */
|
||||
#define MAF_STRATEGY_DOMAIN (1<<5) /* domain */
|
||||
#define MAF_STRATEGY_PMS (1<<6) /* parent matches subdomain */
|
||||
#define MAF_STRATEGY_PMDS (1<<7) /* parent matches dot-subdomain */
|
||||
#define MAF_STRATEGY_LOCALPART_AT \
|
||||
(1<<8) /* localpart@ (maybe localpart+ext@) */
|
||||
|
||||
#define MAIL_ADDR_FIND_DEFAULT (MAIL_ADDR_FIND_FULL | MAIL_ADDR_FIND_NOEXT \
|
||||
| MAIL_ADDR_FIND_LOCALPART_IF_LOCAL \
|
||||
| MAIL_ADDR_FIND_ATDOMAIN)
|
||||
#define MAF_STRATEGY_DEFAULT (MAF_STRATEGY_FULL | MAF_STRATEGY_NOEXT \
|
||||
| MAF_STRATEGY_LOCALPART_IF_LOCAL \
|
||||
| MAF_STRATEGY_AT_DOMAIN)
|
||||
|
||||
/* The least-overhead form. */
|
||||
#define mail_addr_find_int_to_ext(maps, address, extension) \
|
||||
mail_addr_find_opt((maps), (address), (extension), \
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL, \
|
||||
MAIL_ADDR_FIND_DEFAULT)
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAF_STRATEGY_DEFAULT)
|
||||
|
||||
/* The legacy form. */
|
||||
extern const char *mail_addr_find_strategy(MAPS *, const char *, char **, int);
|
||||
/* The legacy forms. */
|
||||
#define MAF_FORM_LEGACY \
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL_FIRST, \
|
||||
MAIL_ADDR_FORM_EXTERNAL
|
||||
|
||||
#define mail_addr_find_strategy(maps, address, extension, strategy) \
|
||||
mail_addr_find_opt((maps), (address), (extension), \
|
||||
MAF_FORM_LEGACY, (strategy))
|
||||
|
||||
#define mail_addr_find(maps, address, extension) \
|
||||
mail_addr_find_strategy((maps), (address), (extension), \
|
||||
MAIL_ADDR_FIND_DEFAULT)
|
||||
MAF_STRATEGY_DEFAULT)
|
||||
|
||||
#define mail_addr_find_to_internal(maps, address, extension) \
|
||||
mail_addr_find_opt((maps), (address), (extension), \
|
||||
MAF_FORM_LEGACY, MAF_STRATEGY_DEFAULT)
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@@ -4,78 +4,94 @@
|
||||
# The last fields are optional.
|
||||
|
||||
echo ==== no search string extension
|
||||
$VALGRIND ./mail_addr_find 'inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}' <<'EOF'
|
||||
internal:external:default:plain1@1.example:plain2@2.example
|
||||
internal:external:default:aa bb@cc.example:"dd ee"@dd.example
|
||||
external:external:default:"aa bb"@cc.example:"dd ee"@dd.example
|
||||
external:internal:default:"aa bb"@cc.example:dd ee@dd.example
|
||||
noconv:noconv:default:plain1@1.example:plain2@2.example
|
||||
noconv:noconv:default:aa bb@cc.example
|
||||
noconv:noconv:default:"aa bb"@cc.example:"dd ee"@dd.example
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}
|
||||
internal:external:external:default:plain1@1.example:plain2@2.example
|
||||
internal:external:external:default:aa bb@cc.example:"dd ee"@dd.example
|
||||
external:external:external:default:"aa bb"@cc.example:"dd ee"@dd.example
|
||||
external:external:internal:default:"aa bb"@cc.example:dd ee@dd.example
|
||||
internal:internal:external:default:plain1@1.example:plain2@2.example
|
||||
internal:internal:external:default:aa bb@cc.example
|
||||
internal:internal:external:default:"aa bb"@cc.example:"dd ee"@dd.example
|
||||
EOF
|
||||
|
||||
echo ==== with search string extension
|
||||
$VALGRIND ./mail_addr_find 'inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}' <<'EOF'
|
||||
internal:external:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
internal:external:default:aa bb+ax bx@cc.example:"dd ee"@dd.example:+ax bx
|
||||
external:external:default:"aa bb+ax bx"@cc.example:"dd ee"@dd.example:+ax bx
|
||||
external:internal:default:"aa bb+ax bx"@cc.example:dd ee@dd.example:+ax bx
|
||||
noconv:noconv:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
noconv:noconv:default:"aa bb+ax bx"@cc.example
|
||||
noconv:noconv:default:"aa bb"+ax bx@cc.example:"dd ee"@dd.example:+ax bx
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}
|
||||
internal:external:external:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
internal:external:external:default:aa bb+ax bx@cc.example:"dd ee"@dd.example:+ax bx
|
||||
external:external:external:default:"aa bb+ax bx"@cc.example:"dd ee"@dd.example:+ax bx
|
||||
external:external:internal:default:"aa bb+ax bx"@cc.example:dd ee@dd.example:+ax bx
|
||||
internal:internal:external:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
internal:internal:external:default:"aa bb+ax bx"@cc.example
|
||||
internal:internal:external:default:"aa bb"+ax bx@cc.example:"dd ee"@dd.example:+ax bx
|
||||
EOF
|
||||
|
||||
echo ==== at in localpart
|
||||
$VALGRIND ./mail_addr_find 'inline:{"a@b"=foo@example,"a.b."=bar@example}' <<'EOF'
|
||||
external:external:default:"a@b"@localhost.localdomain:foo@example
|
||||
external:external:default:"a@b+ext"@localhost.localdomain:foo@example:+ext
|
||||
external:external:default:"a.b."@localhost.localdomain:bar@example
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{"a@b"=foo@example,"a.b."=bar@example}
|
||||
external:external:external:default:"a@b"@localhost.localdomain:foo@example
|
||||
external:external:external:default:"a@b+ext"@localhost.localdomain:foo@example:+ext
|
||||
external:external:external:default:"a.b."@localhost.localdomain:bar@example
|
||||
EOF
|
||||
|
||||
echo ==== legacy support
|
||||
$VALGRIND ./mail_addr_find 'inline:{"a@b"=extern-1@example,a@b=intern-1@example,a.b.=intern-2@example}' <<'EOF'
|
||||
compat:compat:default:a@b@localhost.localdomain:extern-1@example
|
||||
compat:compat:default:a.b.@localhost.localdomain:intern-2@example
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{"a@b"=extern-1@example,a@b=intern-1@example,a.b.=intern-2@example}
|
||||
internal:external-first:external:default:a@b@localhost.localdomain:extern-1@example
|
||||
internal:external-first:external:default:a.b.@localhost.localdomain:intern-2@example
|
||||
EOF
|
||||
|
||||
echo ==== atdomain test
|
||||
$VALGRIND ./mail_addr_find 'inline:{plain1@1.example=plain2@2.example,@3.example=plain4@4.example,plain5@3.example=plain6@6.example}' <<'EOF'
|
||||
external:external:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
external:external:default:plain2@2.example:
|
||||
external:external:default:plain3@3.example:plain4@4.example
|
||||
external:external:default:plain5@3.example:plain6@6.example
|
||||
echo ==== at_domain test
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{plain1@1.example=plain2@2.example,@3.example=plain4@4.example,plain5@3.example=plain6@6.example}
|
||||
external:external:external:default:plain1+ext@1.example:plain2@2.example:+ext
|
||||
external:external:external:default:plain2@2.example:
|
||||
external:external:external:default:plain3@3.example:plain4@4.example
|
||||
external:external:external:default:plain5@3.example:plain6@6.example
|
||||
EOF
|
||||
|
||||
echo ==== domain test
|
||||
$VALGRIND ./mail_addr_find 'inline:{plain1@1.example=plain2@2.example,3.example=plain4@4.example,plain5@3.example=plain6@6.example}' <<'EOF'
|
||||
external:external:full|noext|domain:plain1+ext@1.example:plain2@2.example:+ext
|
||||
external:external:full|noext|domain:plain2@2.example:
|
||||
external:external:full|noext|domain:plain3@3.example:plain4@4.example
|
||||
external:external:full|noext|domain:plain5@3.example:plain6@6.example
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{plain1@1.example=plain2@2.example,3.example=plain4@4.example,plain5@3.example=plain6@6.example}
|
||||
external:external:external:full|noext|domain:plain1+ext@1.example:plain2@2.example:+ext
|
||||
external:external:external:full|noext|domain:plain2@2.example:
|
||||
external:external:external:full|noext|domain:plain3@3.example:plain4@4.example
|
||||
external:external:external:full|noext|domain:plain5@3.example:plain6@6.example
|
||||
EOF
|
||||
|
||||
echo ==== atdomain for local domain
|
||||
$VALGRIND ./mail_addr_find 'inline:{ab=foo@example,@localhost.localdomain=@bar.example}' <<'EOF'
|
||||
external:external:default:ab@localhost.localdomain:foo@example:
|
||||
external:external:default:cd@localhost.localdomain:@bar.example
|
||||
echo ==== at_domain for local domain
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{ab=foo@example,@localhost.localdomain=@bar.example}
|
||||
external:external:external:default:ab@localhost.localdomain:foo@example:
|
||||
external:external:external:default:cd@localhost.localdomain:@bar.example
|
||||
EOF
|
||||
|
||||
echo ==== localat and domain test
|
||||
$VALGRIND ./mail_addr_find 'inline:{ab@=foo@example,localhost.localdomain=@bar.example}' <<'EOF'
|
||||
internal:external:localpart_at_if_local|domain:ab@localhost.localdomain:foo@example:
|
||||
internal:external:localpart_at_if_local|noext|domain:ab+ext@localhost.localdomain:foo@example:+ext
|
||||
internal:external:localpart_at_if_local|domain:cd@localhost.localdomain:@bar.example
|
||||
echo ==== localpart_at_if_local and domain test
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{ab@=foo@example,localhost.localdomain=@bar.example}
|
||||
internal:external:external:localpart_at_if_local|domain:ab@localhost.localdomain:foo@example:
|
||||
internal:external:external:localpart_at_if_local|noext|domain:ab+ext@localhost.localdomain:foo@example:+ext
|
||||
internal:external:external:localpart_at_if_local|domain:cd@localhost.localdomain:@bar.example
|
||||
EOF
|
||||
|
||||
echo ==== localpart_at has less precedence than domain test
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{ab@=foo@example,localhost.localdomain=@bar.example}
|
||||
external:external:external:localpart_at|domain:ab@localhost.localdomain:@bar.example:
|
||||
external:external:external:localpart_at|domain:ab@foo:foo@example
|
||||
EOF
|
||||
|
||||
echo ==== domain and subdomain test
|
||||
$VALGRIND ./mail_addr_find 'inline:{example=example-result,.example=dot-example-result}' <<'EOF'
|
||||
external:external:domain:plain1+ext@1.example
|
||||
external:external:domain:foo@sub.example
|
||||
external:external:domain:foo@example:example-result
|
||||
external:external:domain|pms:foo@example:example-result
|
||||
external:external:domain|pms:foo@sub.example:example-result
|
||||
external:external:domain|pms:foo@sub.sub.example:example-result
|
||||
external:external:domain|pmds:foo@example:example-result
|
||||
external:external:domain|pmds:foo@sub.example:dot-example-result
|
||||
external:external:domain|pmds:foo@sub.sub.example:dot-example-result
|
||||
$VALGRIND ./mail_addr_find <<'EOF'
|
||||
inline:{example=example-result,.example=dot-example-result}
|
||||
external:external:external:domain:plain1+ext@1.example
|
||||
external:external:external:domain:foo@sub.example
|
||||
external:external:external:domain:foo@example:example-result
|
||||
external:external:external:domain|pms:foo@example:example-result
|
||||
external:external:external:domain|pms:foo@sub.example:example-result
|
||||
external:external:external:domain|pms:foo@sub.sub.example:example-result
|
||||
external:external:external:domain|pmds:foo@example:example-result
|
||||
external:external:external:domain|pmds:foo@sub.example:dot-example-result
|
||||
external:external:external:domain|pmds:foo@sub.sub.example:dot-example-result
|
||||
EOF
|
||||
|
@@ -1,50 +1,63 @@
|
||||
==== no search string extension
|
||||
internal:plain1@1.example -> external:plain2@2.example (null extension)
|
||||
internal:aa bb@cc.example -> external:"dd ee"@dd.example (null extension)
|
||||
external:"aa bb"@cc.example -> external:"dd ee"@dd.example (null extension)
|
||||
external:"aa bb"@cc.example -> internal:dd ee@dd.example (null extension)
|
||||
noconv:plain1@1.example -> noconv:plain2@2.example (null extension)
|
||||
noconv:aa bb@cc.example -> noconv:(not found) (null extension)
|
||||
noconv:"aa bb"@cc.example -> noconv:"dd ee"@dd.example (null extension)
|
||||
inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}
|
||||
internal:plain1@1.example -external-> external:plain2@2.example (null extension)
|
||||
internal:aa bb@cc.example -external-> external:"dd ee"@dd.example (null extension)
|
||||
external:"aa bb"@cc.example -external-> external:"dd ee"@dd.example (null extension)
|
||||
external:"aa bb"@cc.example -external-> internal:dd ee@dd.example (null extension)
|
||||
internal:plain1@1.example -internal-> external:plain2@2.example (null extension)
|
||||
internal:aa bb@cc.example -internal-> external:(not found) (null extension)
|
||||
internal:"aa bb"@cc.example -internal-> external:"dd ee"@dd.example (null extension)
|
||||
==== with search string extension
|
||||
internal:plain1+ext@1.example -> external:plain2@2.example (+ext)
|
||||
internal:aa bb+ax bx@cc.example -> external:"dd ee"@dd.example (+ax bx)
|
||||
external:"aa bb+ax bx"@cc.example -> external:"dd ee"@dd.example (+ax bx)
|
||||
external:"aa bb+ax bx"@cc.example -> internal:dd ee@dd.example (+ax bx)
|
||||
noconv:plain1+ext@1.example -> noconv:plain2@2.example (+ext)
|
||||
noconv:"aa bb+ax bx"@cc.example -> noconv:(not found) (null extension)
|
||||
noconv:"aa bb"+ax bx@cc.example -> noconv:"dd ee"@dd.example (+ax bx)
|
||||
inline:{plain1@1.example=plain2@2.example,{"aa bb"@cc.example="dd ee"@dd.example}}
|
||||
internal:plain1+ext@1.example -external-> external:plain2@2.example (+ext)
|
||||
internal:aa bb+ax bx@cc.example -external-> external:"dd ee"@dd.example (+ax bx)
|
||||
external:"aa bb+ax bx"@cc.example -external-> external:"dd ee"@dd.example (+ax bx)
|
||||
external:"aa bb+ax bx"@cc.example -external-> internal:dd ee@dd.example (+ax bx)
|
||||
internal:plain1+ext@1.example -internal-> external:plain2@2.example (+ext)
|
||||
internal:"aa bb+ax bx"@cc.example -internal-> external:(not found) (null extension)
|
||||
internal:"aa bb"+ax bx@cc.example -internal-> external:"dd ee"@dd.example (+ax bx)
|
||||
==== at in localpart
|
||||
external:"a@b"@localhost.localdomain -> external:foo@example (null extension)
|
||||
external:"a@b+ext"@localhost.localdomain -> external:foo@example (+ext)
|
||||
external:"a.b."@localhost.localdomain -> external:bar@example (null extension)
|
||||
inline:{"a@b"=foo@example,"a.b."=bar@example}
|
||||
external:"a@b"@localhost.localdomain -external-> external:foo@example (null extension)
|
||||
external:"a@b+ext"@localhost.localdomain -external-> external:foo@example (+ext)
|
||||
external:"a.b."@localhost.localdomain -external-> external:bar@example (null extension)
|
||||
==== legacy support
|
||||
compat:a@b@localhost.localdomain -> compat:extern-1@example (null extension)
|
||||
compat:a.b.@localhost.localdomain -> compat:intern-2@example (null extension)
|
||||
==== atdomain test
|
||||
external:plain1+ext@1.example -> external:plain2@2.example (+ext)
|
||||
external:plain2@2.example -> external:(not found) (null extension)
|
||||
external:plain3@3.example -> external:plain4@4.example (null extension)
|
||||
external:plain5@3.example -> external:plain6@6.example (null extension)
|
||||
inline:{"a@b"=extern-1@example,a@b=intern-1@example,a.b.=intern-2@example}
|
||||
internal:a@b@localhost.localdomain -external-first-> external:extern-1@example (null extension)
|
||||
internal:a.b.@localhost.localdomain -external-first-> external:intern-2@example (null extension)
|
||||
==== at_domain test
|
||||
inline:{plain1@1.example=plain2@2.example,@3.example=plain4@4.example,plain5@3.example=plain6@6.example}
|
||||
external:plain1+ext@1.example -external-> external:plain2@2.example (+ext)
|
||||
external:plain2@2.example -external-> external:(not found) (null extension)
|
||||
external:plain3@3.example -external-> external:plain4@4.example (null extension)
|
||||
external:plain5@3.example -external-> external:plain6@6.example (null extension)
|
||||
==== domain test
|
||||
external:plain1+ext@1.example -> external:plain2@2.example (+ext)
|
||||
external:plain2@2.example -> external:(not found) (null extension)
|
||||
external:plain3@3.example -> external:plain4@4.example (null extension)
|
||||
external:plain5@3.example -> external:plain6@6.example (null extension)
|
||||
==== atdomain for local domain
|
||||
external:ab@localhost.localdomain -> external:foo@example (null extension)
|
||||
external:cd@localhost.localdomain -> external:@bar.example (null extension)
|
||||
==== localat and domain test
|
||||
internal:ab@localhost.localdomain -> external:foo@example (null extension)
|
||||
internal:ab+ext@localhost.localdomain -> external:foo@example (+ext)
|
||||
internal:cd@localhost.localdomain -> external:@bar.example (null extension)
|
||||
inline:{plain1@1.example=plain2@2.example,3.example=plain4@4.example,plain5@3.example=plain6@6.example}
|
||||
external:plain1+ext@1.example -external-> external:plain2@2.example (+ext)
|
||||
external:plain2@2.example -external-> external:(not found) (null extension)
|
||||
external:plain3@3.example -external-> external:plain4@4.example (null extension)
|
||||
external:plain5@3.example -external-> external:plain6@6.example (null extension)
|
||||
==== at_domain for local domain
|
||||
inline:{ab=foo@example,@localhost.localdomain=@bar.example}
|
||||
external:ab@localhost.localdomain -external-> external:foo@example (null extension)
|
||||
external:cd@localhost.localdomain -external-> external:@bar.example (null extension)
|
||||
==== localpart_at_if_local and domain test
|
||||
inline:{ab@=foo@example,localhost.localdomain=@bar.example}
|
||||
internal:ab@localhost.localdomain -external-> external:foo@example (null extension)
|
||||
internal:ab+ext@localhost.localdomain -external-> external:foo@example (+ext)
|
||||
internal:cd@localhost.localdomain -external-> external:@bar.example (null extension)
|
||||
==== localpart_at has less precedence than domain test
|
||||
inline:{ab@=foo@example,localhost.localdomain=@bar.example}
|
||||
external:ab@localhost.localdomain -external-> external:@bar.example (null extension)
|
||||
external:ab@foo -external-> external:foo@example (null extension)
|
||||
==== domain and subdomain test
|
||||
external:plain1+ext@1.example -> external:(not found) (null extension)
|
||||
external:foo@sub.example -> external:(not found) (null extension)
|
||||
external:foo@example -> external:example-result (null extension)
|
||||
external:foo@example -> external:example-result (null extension)
|
||||
external:foo@sub.example -> external:example-result (null extension)
|
||||
external:foo@sub.sub.example -> external:example-result (null extension)
|
||||
external:foo@example -> external:example-result (null extension)
|
||||
external:foo@sub.example -> external:dot-example-result (null extension)
|
||||
external:foo@sub.sub.example -> external:dot-example-result (null extension)
|
||||
inline:{example=example-result,.example=dot-example-result}
|
||||
external:plain1+ext@1.example -external-> external:(not found) (null extension)
|
||||
external:foo@sub.example -external-> external:(not found) (null extension)
|
||||
external:foo@example -external-> external:example-result (null extension)
|
||||
external:foo@example -external-> external:example-result (null extension)
|
||||
external:foo@sub.example -external-> external:example-result (null extension)
|
||||
external:foo@sub.sub.example -external-> external:example-result (null extension)
|
||||
external:foo@example -external-> external:example-result (null extension)
|
||||
external:foo@sub.example -external-> external:dot-example-result (null extension)
|
||||
external:foo@sub.sub.example -external-> external:dot-example-result (null extension)
|
||||
|
@@ -11,9 +11,9 @@
|
||||
/* const char *mail_addr_form_to_string(int addr_form)
|
||||
/* DESCRIPTION
|
||||
/* mail_addr_form_from_string() converts a symbolic mail address
|
||||
/* form name ("internal", "external", "noconv") into the
|
||||
/* corresponding internal code. The result is -1 if an
|
||||
/* unrecognized name was specified.
|
||||
/* form name ("internal", "external", "internal-first") into the
|
||||
/* corresponding internal code. The result is -1 if an unrecognized
|
||||
/* name was specified.
|
||||
/*
|
||||
/* mail_addr_form_to_string() converts from internal code
|
||||
/* to the corresponding symbolic name. The result is null if
|
||||
@@ -47,7 +47,7 @@
|
||||
static const NAME_CODE addr_form_table[] = {
|
||||
"external", MAIL_ADDR_FORM_EXTERNAL,
|
||||
"internal", MAIL_ADDR_FORM_INTERNAL,
|
||||
"noconv", MAIL_ADDR_FORM_NOCONV,
|
||||
"external-first", MAIL_ADDR_FORM_EXTERNAL_FIRST,
|
||||
0, -1,
|
||||
};
|
||||
|
||||
|
@@ -12,12 +12,11 @@
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* External interface. The MAIL_ADDR_FORM_NOCONV is for legacy code that
|
||||
* hasn't yet been converted to external-form address lookups.
|
||||
* External interface.
|
||||
*/
|
||||
#define MAIL_ADDR_FORM_NOCONV 0 /* do not convert */
|
||||
#define MAIL_ADDR_FORM_INTERNAL 1 /* unquoted form */
|
||||
#define MAIL_ADDR_FORM_EXTERNAL 2 /* quoted form */
|
||||
#define MAIL_ADDR_FORM_EXTERNAL_FIRST 3 /* quoted form, then unquoted */
|
||||
|
||||
extern int mail_addr_form_from_string(const char *);
|
||||
extern const char *mail_addr_form_to_string(int);
|
||||
|
@@ -11,11 +11,14 @@
|
||||
/* const char *address;
|
||||
/* int propagate;
|
||||
/*
|
||||
/* ARGV *mail_addr_map_opt(path, address, propagate, in_form, out_form)
|
||||
/* ARGV *mail_addr_map_opt(path, address, propagate, in_form,
|
||||
/* query_form, out_form)
|
||||
/* MAPS *path;
|
||||
/* const char *address;
|
||||
/* int propagate;
|
||||
/* int how;
|
||||
/* int in_form;
|
||||
/* int query_form;
|
||||
/* int out_form;
|
||||
/* DESCRIPTION
|
||||
/* mail_addr_map_*() returns the translation for the named address,
|
||||
/* or a null pointer if none is found.
|
||||
@@ -35,18 +38,17 @@
|
||||
/* form \fI@otherdomain\fR, the result is the original user in
|
||||
/* \fIotherdomain\fR.
|
||||
/*
|
||||
/* mail_addr_map_opt() gives additional control over whether the
|
||||
/* input is in internal (unquoted) or external (quoted) form.
|
||||
/* to internal form and invokes mail_addr_map_int_to_ext().
|
||||
/* This may introduce additional unqoute822_local() and
|
||||
/* quote_833_local() calls.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP path
|
||||
/* Dictionary search path (see maps(3)).
|
||||
/* .IP address
|
||||
/* The address to be looked up in external (quoted) form, or
|
||||
/* in the form specified with the in_form argument.
|
||||
/* .IP query_form
|
||||
/* Database query address forms, either MAIL_ADDR_FORM_INTERNAL
|
||||
/* (unquoted form), MAIL_ADDR_FORM_EXTERNAL_FIRST (external, then
|
||||
/* internal if the forms differ) or MAIL_ADDR_FORM_EXTERNAL
|
||||
/* (quoted form).
|
||||
/* .IP in_form
|
||||
/* .IP out_form
|
||||
/* Input and output address forms, either MAIL_ADDR_FORM_INTERNAL
|
||||
@@ -98,7 +100,7 @@
|
||||
/* mail_addr_map - map a canonical address */
|
||||
|
||||
ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
int in_form, int out_form)
|
||||
int in_form, int query_form, int out_form)
|
||||
{
|
||||
VSTRING *buffer = 0;
|
||||
const char *myname = "mail_addr_map";
|
||||
@@ -111,16 +113,9 @@ ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
VSTRING *ext_address = 0;
|
||||
const char *int_addr;
|
||||
|
||||
/* Crutch until we can retire MAIL_ADDR_FORM_NOCONV. */
|
||||
int mid_form = (out_form == MAIL_ADDR_FORM_NOCONV ?
|
||||
MAIL_ADDR_FORM_NOCONV : MAIL_ADDR_FORM_EXTERNAL);
|
||||
|
||||
/*
|
||||
* Optionally convert input from external form. We prefer internal-form
|
||||
* input to avoid an unnecessary input conversion in
|
||||
* mail_addr_find_opt(). But the consequence is that we have to convert
|
||||
* the internal-form input's localpart to external form when mapping
|
||||
* @domain -> @domain.
|
||||
* input to avoid unnecessary input conversion in mail_addr_find_opt().
|
||||
*/
|
||||
if (in_form == MAIL_ADDR_FORM_EXTERNAL) {
|
||||
int_address = vstring_alloc(100);
|
||||
@@ -134,16 +129,16 @@ ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
/*
|
||||
* Look up the full address; if no match is found, look up the address
|
||||
* with the extension stripped off, and remember the unmatched extension.
|
||||
* We explicitly call the mail_addr_find_opt() variant that does not
|
||||
* convert the lookup result.
|
||||
*/
|
||||
if ((string = mail_addr_find_opt(path, int_addr, &extension,
|
||||
in_form, mid_form,
|
||||
MAIL_ADDR_FIND_DEFAULT)) != 0) {
|
||||
in_form, query_form,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAF_STRATEGY_DEFAULT)) != 0) {
|
||||
|
||||
/*
|
||||
* Prepend the original user to @otherdomain, but do not propagate
|
||||
* the unmatched address extension.
|
||||
* the unmatched address extension. Convert the address to external
|
||||
* form just like the mail_addr_find_opt() output.
|
||||
*/
|
||||
if (*string == '@') {
|
||||
buffer = vstring_alloc(100);
|
||||
@@ -153,9 +148,9 @@ ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
vstring_strcpy(buffer, int_addr);
|
||||
if (extension)
|
||||
vstring_truncate(buffer, LEN(buffer) - strlen(extension));
|
||||
ext_address = vstring_alloc(100);
|
||||
vstring_strcat(buffer, string);
|
||||
ext_address = vstring_alloc(2 * LEN(buffer));
|
||||
quote_822_local(ext_address, STR(buffer));
|
||||
vstring_strcat(ext_address, string);
|
||||
string = STR(ext_address);
|
||||
}
|
||||
|
||||
@@ -164,7 +159,7 @@ ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
* each address found.
|
||||
*/
|
||||
argv = mail_addr_crunch_opt(string, propagate ? extension : 0,
|
||||
mid_form, out_form);
|
||||
MAIL_ADDR_FORM_EXTERNAL, out_form);
|
||||
if (buffer)
|
||||
vstring_free(buffer);
|
||||
if (ext_address)
|
||||
@@ -199,3 +194,334 @@ ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
|
||||
|
||||
return (argv);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
* SYNOPSIS
|
||||
* mail_addr_map pass_tests | fail_tests
|
||||
* DESCRIPTION
|
||||
* mail_addr_map performs the specified set of built-in
|
||||
* unit tests. With 'pass_tests', all tests must pass, and
|
||||
* with 'fail_tests' all tests must fail.
|
||||
* DIAGNOSTICS
|
||||
* When a unit test fails, the program prints details of the
|
||||
* failed test.
|
||||
*
|
||||
* The program terminates with a non-zero exit status when at
|
||||
* least one test does not pass with 'pass_tests', or when at
|
||||
* least one test does not fail with 'fail_tests'.
|
||||
*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <argv.h>
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <vstring.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <canon_addr.h>
|
||||
#include <mail_addr_map.h>
|
||||
#include <mail_conf.h> /* XXX eliminate main.cf dependency */
|
||||
#include <mail_params.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#define STR vstring_str
|
||||
|
||||
typedef struct {
|
||||
const char *testname;
|
||||
const char *database;
|
||||
int propagate;
|
||||
const char *delimiter;
|
||||
int in_form;
|
||||
int query_form;
|
||||
int out_form;
|
||||
const char *address;
|
||||
const char *expect_argv[2];
|
||||
int expect_argc;
|
||||
} MAIL_ADDR_MAP_TEST;
|
||||
|
||||
#define DONT_PROPAGATE_UNMATCHED_EXTENSION 0
|
||||
#define DO_PROPAGATE_UNMATCHED_EXTENSION 1
|
||||
#define NO_RECIPIENT_DELIMITER ""
|
||||
#define PLUS_RECIPIENT_DELIMITER "+"
|
||||
|
||||
/*
|
||||
* All these tests must pass, so that we know that mail_addr_map_opt() works
|
||||
* as intended. mail_addr_map() has always been used for maps that expect
|
||||
* external-form queries, so there are no tests here for internal-form
|
||||
* queries.
|
||||
*/
|
||||
static MAIL_ADDR_MAP_TEST pass_tests[] = {
|
||||
{
|
||||
"1 external -external-> external, no extension",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa@example.com",
|
||||
{"bb@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"2 external -external-> external, extension, propagation",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa+ext@example.com",
|
||||
{"bb+ext@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"3 external -external-> external, extension, no propagation, no match",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DONT_PROPAGATE_UNMATCHED_EXTENSION, NO_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa+ext@example.com",
|
||||
{0}, 0,
|
||||
},
|
||||
{
|
||||
"4 external -external-> external, extension, full match",
|
||||
"inline:{{cc+ext@example.com=dd@example.com,ee@example.com}}",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"cc+ext@example.com",
|
||||
{"dd@example.com", "ee@example.com"}, 2,
|
||||
},
|
||||
{
|
||||
"5 external -external-> external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{"\"b b\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"6 external -external-> external, extension, propagation, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a+ext\"@example.com",
|
||||
{"\"b b+ext\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"7 internal -external-> internal, no extension, propagation, embedded space",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_INTERNAL,
|
||||
"a a@example.com",
|
||||
{"b b@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"8 internal -external-> internal, extension, propagation, embedded space",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_INTERNAL,
|
||||
"a a+ext@example.com",
|
||||
{"b b+ext@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"9 internal -external-> internal, no extension, propagation, embedded space",
|
||||
"inline:{ {a_a@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_INTERNAL,
|
||||
"a_a@example.com",
|
||||
{"b b@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"10 internal -external-> internal, extension, propagation, embedded space",
|
||||
"inline:{ {a_a@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_INTERNAL,
|
||||
"a_a+ext@example.com",
|
||||
{"b b+ext@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"11 internal -external-> internal, no extension, @domain",
|
||||
"inline:{ {@example.com=@example.net} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"a@a@example.com",
|
||||
{"\"a@a\"@example.net"}, 1,
|
||||
},
|
||||
0,
|
||||
};
|
||||
|
||||
/*
|
||||
* All these tests must fail, so that we know that the tests work.
|
||||
*/
|
||||
static MAIL_ADDR_MAP_TEST fail_tests[] = {
|
||||
{
|
||||
"selftest 1 external -external-> external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{"\"bXb\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"selftest 2 external -external-> external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"aXa\"@example.com",
|
||||
{"\"b b\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"selftest 3 external -external-> external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{0}, 0,
|
||||
},
|
||||
0,
|
||||
};
|
||||
|
||||
/* canon_addr_external - surrogate to avoid trivial-rewrite dependency */
|
||||
|
||||
VSTRING *canon_addr_external(VSTRING *result, const char *addr)
|
||||
{
|
||||
return (vstring_strcpy(result, addr));
|
||||
}
|
||||
|
||||
static int compare(const char *testname,
|
||||
const char **expect_argv, int expect_argc,
|
||||
char **result_argv, int result_argc)
|
||||
{
|
||||
int n;
|
||||
int err = 0;
|
||||
|
||||
if (expect_argc != 0 && result_argc != 0) {
|
||||
for (n = 0; n < expect_argc && n < result_argc; n++) {
|
||||
if (strcmp(expect_argv[n], result_argv[n]) != 0) {
|
||||
msg_warn("fail test %s: expect[%d]='%s', result[%d]='%s'",
|
||||
testname, n, expect_argv[n], n, result_argv[n]);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expect_argc != result_argc) {
|
||||
msg_warn("fail test %s: expects %d results but there were %d",
|
||||
testname, expect_argc, result_argc);
|
||||
for (n = expect_argc; n < result_argc; n++)
|
||||
msg_info("no expect to match result[%d]='%s'", n, result_argv[n]);
|
||||
for (n = result_argc; n < expect_argc; n++)
|
||||
msg_info("no result to match expect[%d]='%s'", n, expect_argv[n]);
|
||||
err = 1;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static char *progname;
|
||||
|
||||
static NORETURN usage(void)
|
||||
{
|
||||
msg_fatal("usage: %s pass_test | fail_test", progname);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MAIL_ADDR_MAP_TEST *test;
|
||||
MAIL_ADDR_MAP_TEST *tests;
|
||||
int errs = 0;
|
||||
|
||||
#define UPDATE(dst, src) { if (dst) myfree(dst); dst = mystrdup(src); }
|
||||
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
progname = argv[0];
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
} else if (strcmp(argv[1], "pass_tests") == 0) {
|
||||
tests = pass_tests;
|
||||
} else if (strcmp(argv[1], "fail_tests") == 0) {
|
||||
tests = fail_tests;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
mail_conf_read(); /* XXX eliminate */
|
||||
|
||||
/*
|
||||
* A read-eval-print loop, because specifying C strings with quotes and
|
||||
* backslashes is painful.
|
||||
*/
|
||||
for (test = tests; test->testname; test++) {
|
||||
ARGV *result;
|
||||
int fail = 0;
|
||||
|
||||
if (mail_addr_form_to_string(test->in_form) == 0) {
|
||||
msg_warn("test %s: bad in_form field: %d",
|
||||
test->testname, test->in_form);
|
||||
fail = 1;
|
||||
continue;
|
||||
}
|
||||
if (mail_addr_form_to_string(test->query_form) == 0) {
|
||||
msg_warn("test %s: bad query_form field: %d",
|
||||
test->testname, test->query_form);
|
||||
fail = 1;
|
||||
continue;
|
||||
}
|
||||
if (mail_addr_form_to_string(test->out_form) == 0) {
|
||||
msg_warn("test %s: bad out_form field: %d",
|
||||
test->testname, test->out_form);
|
||||
fail = 1;
|
||||
continue;
|
||||
}
|
||||
MAPS *maps = maps_create("test", test->database, DICT_FLAG_LOCK
|
||||
| DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
|
||||
|
||||
UPDATE(var_rcpt_delim, test->delimiter);
|
||||
result = mail_addr_map_opt(maps, test->address, test->propagate,
|
||||
test->in_form, test->query_form, test->out_form);
|
||||
if (compare(test->testname, test->expect_argv, test->expect_argc,
|
||||
result ? result->argv : 0, result ? result->argc : 0) != 0) {
|
||||
msg_info("database = %s", test->database);
|
||||
msg_info("propagate = %d", test->propagate);
|
||||
msg_info("delimiter = '%s'", var_rcpt_delim);
|
||||
msg_info("in_form = %s", mail_addr_form_to_string(test->in_form));
|
||||
msg_info("query_form = %s", mail_addr_form_to_string(test->query_form));
|
||||
msg_info("out_form = %s", mail_addr_form_to_string(test->out_form));
|
||||
msg_info("address = %s", test->address);
|
||||
fail = 1;
|
||||
}
|
||||
maps_free(maps);
|
||||
if (result)
|
||||
argv_free(result);
|
||||
|
||||
/*
|
||||
* It is an error if a test does not pass or fail as intended.
|
||||
*/
|
||||
errs += (tests == pass_tests ? fail : !fail);
|
||||
}
|
||||
return (errs != 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -25,12 +25,13 @@
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern ARGV *mail_addr_map_opt(MAPS *, const char *, int, int, int);
|
||||
extern ARGV *mail_addr_map_opt(MAPS *, const char *, int, int, int, int);
|
||||
|
||||
/* The least-overhead form. */
|
||||
#define mail_addr_map_internal(path, address, propagate) \
|
||||
mail_addr_map_opt((path), (address), (propagate), \
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL)
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL, \
|
||||
MAIL_ADDR_FORM_INTERNAL)
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@@ -1,23 +1,26 @@
|
||||
unknown: warning: fail test selftest 1 external to external, no extension, quoted: expect[0]='"bXb"@example.com', result[0]='"b b"@example.com'
|
||||
unknown: warning: fail test selftest 1 external -external-> external, no extension, quoted: expect[0]='"bXb"@example.com', result[0]='"b b"@example.com'
|
||||
unknown: database = inline:{ {"a a"@example.com="b b"@example.com} }
|
||||
unknown: propagate = 1
|
||||
unknown: delimiter = '+'
|
||||
unknown: in_form = external
|
||||
unknown: query_form = external
|
||||
unknown: out_form = external
|
||||
unknown: address = "a a"@example.com
|
||||
unknown: warning: fail test selftest 2 external to external, no extension, quoted: expects 1 results but there were 0
|
||||
unknown: warning: fail test selftest 2 external -external-> external, no extension, quoted: expects 1 results but there were 0
|
||||
unknown: no result to match expect[0]='"b b"@example.com'
|
||||
unknown: database = inline:{ {"a a"@example.com="b b"@example.com} }
|
||||
unknown: propagate = 1
|
||||
unknown: delimiter = '+'
|
||||
unknown: in_form = external
|
||||
unknown: query_form = external
|
||||
unknown: out_form = external
|
||||
unknown: address = "aXa"@example.com
|
||||
unknown: warning: fail test selftest 3 external to external, no extension, quoted: expects 0 results but there were 1
|
||||
unknown: warning: fail test selftest 3 external -external-> external, no extension, quoted: expects 0 results but there were 1
|
||||
unknown: no expect to match result[0]='"b b"@example.com'
|
||||
unknown: database = inline:{ {"a a"@example.com="b b"@example.com} }
|
||||
unknown: propagate = 1
|
||||
unknown: delimiter = '+'
|
||||
unknown: in_form = external
|
||||
unknown: query_form = external
|
||||
unknown: out_form = external
|
||||
unknown: address = "a a"@example.com
|
||||
|
@@ -1,309 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* mail_addr_map_tester 1
|
||||
/* SUMMARY
|
||||
/* mail_addr_map test program
|
||||
/* SYNOPSIS
|
||||
/* mail_addr_map pass_tests | fail_tests
|
||||
/* DESCRIPTION
|
||||
/* mail_addr_map performs the specified set of built-in
|
||||
/* unit tests. With 'pass_tests', all tests must pass, and
|
||||
/* with 'fail_tests' all tests must fail.
|
||||
/* DIAGNOSTICS
|
||||
/* When a unit test fails, the program prints details of the
|
||||
/* failed test.
|
||||
/*
|
||||
/* The program terminates with a non-zero exit status when at
|
||||
/* least one test does not pass with 'pass_tests', or when at
|
||||
/* least one test does not fail with 'fail_tests'.
|
||||
/* SEE ALSO
|
||||
/* mail_addr_map(3), generic address mapping
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <argv.h>
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <vstring.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <canon_addr.h>
|
||||
#include <mail_addr_map.h>
|
||||
#include <mail_conf.h> /* XXX eliminate main.cf dependency */
|
||||
#include <mail_params.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#define STR vstring_str
|
||||
|
||||
typedef struct {
|
||||
const char *testname;
|
||||
const char *database;
|
||||
int propagate;
|
||||
const char *delimiter;
|
||||
int in_form;
|
||||
int out_form;
|
||||
const char *address;
|
||||
const char *expect_argv[2];
|
||||
int expect_argc;
|
||||
} MAIL_ADDR_MAP_TEST;
|
||||
|
||||
#define DONT_PROPAGATE_UNMATCHED_EXTENSION 0
|
||||
#define DO_PROPAGATE_UNMATCHED_EXTENSION 1
|
||||
#define NO_RECIPIENT_DELIMITER ""
|
||||
#define PLUS_RECIPIENT_DELIMITER "+"
|
||||
|
||||
/*
|
||||
* All these tests must pass, so that we know that mail_addr_map_opt() works
|
||||
* as intended.
|
||||
*/
|
||||
static MAIL_ADDR_MAP_TEST pass_tests[] = {
|
||||
{
|
||||
"1 external to external, no extension",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa@example.com",
|
||||
{"bb@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"2 external to external, extension, propagation",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa+ext@example.com",
|
||||
{"bb+ext@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"3 external to external, extension, no propagation, no match",
|
||||
"inline:{ aa@example.com=bb@example.com }",
|
||||
DONT_PROPAGATE_UNMATCHED_EXTENSION, NO_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"aa+ext@example.com",
|
||||
{0}, 0,
|
||||
},
|
||||
{
|
||||
"4 external to external, extension, full match",
|
||||
"inline:{{cc+ext@example.com=dd@example.com,ee@example.com}}",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"cc+ext@example.com",
|
||||
{"dd@example.com", "ee@example.com"}, 2,
|
||||
},
|
||||
{
|
||||
"5 external to external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{"\"b b\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"6 external to external, extension, propagation, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a+ext\"@example.com",
|
||||
{"\"b b+ext\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"7 internal to internal, no extension, propagation, embedded space",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL,
|
||||
"a a@example.com",
|
||||
{"b b@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"8 internal to internal, extension, propagation, embedded space",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL,
|
||||
"a a+ext@example.com",
|
||||
{"b b+ext@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"9 noconv to noconv, no extension, propagation, embedded space",
|
||||
"inline:{ {a_a@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL,
|
||||
"a_a@example.com",
|
||||
{"b b@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"10 noconv to noconv, extension, propagation, embedded space",
|
||||
"inline:{ {a_a@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL,
|
||||
"a_a+ext@example.com",
|
||||
{"b b+ext@example.com"}, 1,
|
||||
},
|
||||
0,
|
||||
};
|
||||
|
||||
/*
|
||||
* All these tests must fail, so that we know that the tests work.
|
||||
*/
|
||||
static MAIL_ADDR_MAP_TEST fail_tests[] = {
|
||||
{
|
||||
"selftest 1 external to external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{"\"bXb\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"selftest 2 external to external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"aXa\"@example.com",
|
||||
{"\"b b\"@example.com"}, 1,
|
||||
},
|
||||
{
|
||||
"selftest 3 external to external, no extension, quoted",
|
||||
"inline:{ {\"a a\"@example.com=\"b b\"@example.com} }",
|
||||
DO_PROPAGATE_UNMATCHED_EXTENSION, PLUS_RECIPIENT_DELIMITER,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL,
|
||||
"\"a a\"@example.com",
|
||||
{0}, 0,
|
||||
},
|
||||
0,
|
||||
};
|
||||
|
||||
/* canon_addr_external - surrogate to avoid trivial-rewrite dependency */
|
||||
|
||||
VSTRING *canon_addr_external(VSTRING *result, const char *addr)
|
||||
{
|
||||
return (vstring_strcpy(result, addr));
|
||||
}
|
||||
|
||||
static int compare(const char *testname,
|
||||
const char **expect_argv, int expect_argc,
|
||||
char **result_argv, int result_argc)
|
||||
{
|
||||
int n;
|
||||
int err = 0;
|
||||
|
||||
if (expect_argc != 0 && result_argc != 0) {
|
||||
for (n = 0; n < expect_argc && n < result_argc; n++) {
|
||||
if (strcmp(expect_argv[n], result_argv[n]) != 0) {
|
||||
msg_warn("fail test %s: expect[%d]='%s', result[%d]='%s'",
|
||||
testname, n, expect_argv[n], n, result_argv[n]);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expect_argc != result_argc) {
|
||||
msg_warn("fail test %s: expects %d results but there were %d",
|
||||
testname, expect_argc, result_argc);
|
||||
for (n = expect_argc; n < result_argc; n++)
|
||||
msg_info("no expect to match result[%d]='%s'", n, result_argv[n]);
|
||||
for (n = result_argc; n < expect_argc; n++)
|
||||
msg_info("no result to match expect[%d]='%s'", n, expect_argv[n]);
|
||||
err = 1;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static char *progname;
|
||||
|
||||
static NORETURN usage(void)
|
||||
{
|
||||
msg_fatal("usage: %s pass_test | fail_test", progname);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MAIL_ADDR_MAP_TEST *test;
|
||||
MAIL_ADDR_MAP_TEST *tests;
|
||||
int errs = 0;
|
||||
|
||||
#define UPDATE(dst, src) { if (dst) myfree(dst); dst = mystrdup(src); }
|
||||
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
progname = argv[0];
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
} else if (strcmp(argv[1], "pass_tests") == 0) {
|
||||
tests = pass_tests;
|
||||
} else if (strcmp(argv[1], "fail_tests") == 0) {
|
||||
tests = fail_tests;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
mail_conf_read(); /* XXX eliminate */
|
||||
|
||||
/*
|
||||
* A read-eval-print loop, because specifying C strings with quotes and
|
||||
* backslashes is painful.
|
||||
*/
|
||||
for (test = tests; test->testname; test++) {
|
||||
ARGV *result;
|
||||
int fail = 0;
|
||||
|
||||
if (mail_addr_form_to_string(test->in_form) == 0) {
|
||||
msg_warn("test %s: bad in_form field: %d",
|
||||
test->testname, test->in_form);
|
||||
fail = 1;
|
||||
continue;
|
||||
}
|
||||
if (mail_addr_form_to_string(test->out_form) == 0) {
|
||||
msg_warn("test %s: bad out_form field: %d",
|
||||
test->testname, test->out_form);
|
||||
fail = 1;
|
||||
continue;
|
||||
}
|
||||
MAPS *maps = maps_create("test", test->database, DICT_FLAG_LOCK
|
||||
| DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
|
||||
|
||||
UPDATE(var_rcpt_delim, test->delimiter);
|
||||
result = mail_addr_map_opt(maps, test->address, test->propagate,
|
||||
test->in_form, test->out_form);
|
||||
if (compare(test->testname, test->expect_argv, test->expect_argc,
|
||||
result ? result->argv : 0, result ? result->argc : 0) != 0) {
|
||||
msg_info("database = %s", test->database);
|
||||
msg_info("propagate = %d", test->propagate);
|
||||
msg_info("delimiter = '%s'", var_rcpt_delim);
|
||||
msg_info("in_form = %s", mail_addr_form_to_string(test->in_form));
|
||||
msg_info("out_form = %s", mail_addr_form_to_string(test->out_form));
|
||||
msg_info("address = %s", test->address);
|
||||
fail = 1;
|
||||
}
|
||||
maps_free(maps);
|
||||
if (result)
|
||||
argv_free(result);
|
||||
|
||||
/*
|
||||
* It is an error if a test does not pass or fail as intended.
|
||||
*/
|
||||
errs += (tests == pass_tests ? fail : !fail);
|
||||
}
|
||||
return (errs != 0);
|
||||
}
|
@@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20170117"
|
||||
#define MAIL_RELEASE_DATE "20170122"
|
||||
#define MAIL_VERSION_NUMBER "3.2"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@@ -48,7 +48,7 @@
|
||||
/* When the \fIkey\fR specifies email address information, the
|
||||
/* localpart should be enclosed with double quotes if required
|
||||
/* by RFC 5322. For example, an address localpart that contains
|
||||
/* ';' or that ends on '.'.
|
||||
/* ";", or a localpart that starts or ends with ".".
|
||||
/*
|
||||
/* By default the lookup key is mapped to lowercase to make
|
||||
/* the lookups case insensitive; as of Postfix 2.3 this case
|
||||
@@ -64,7 +64,7 @@
|
||||
/* .IP \fB-b\fR
|
||||
/* Enable message body query mode. When reading lookup keys
|
||||
/* from standard input with "\fB-q -\fR", process the input
|
||||
/* as if it is an email message in RFC 2822 format. Each line
|
||||
/* as if it is an email message in RFC 5322 format. Each line
|
||||
/* of body content becomes one lookup key.
|
||||
/* .sp
|
||||
/* By default, the \fB-b\fR option starts generating lookup
|
||||
@@ -101,7 +101,7 @@
|
||||
/* .IP \fB-h\fR
|
||||
/* Enable message header query mode. When reading lookup keys
|
||||
/* from standard input with "\fB-q -\fR", process the input
|
||||
/* as if it is an email message in RFC 2822 format. Each
|
||||
/* as if it is an email message in RFC 5322 format. Each
|
||||
/* logical header line becomes one lookup key. A multi-line
|
||||
/* header becomes one lookup key with one or more embedded
|
||||
/* newline characters.
|
||||
|
@@ -81,7 +81,9 @@ int smtp_map11_external(VSTRING *addr, MAPS *maps, int propagate)
|
||||
const char *result;
|
||||
|
||||
if ((new_addr = mail_addr_map_opt(maps, STR(addr), propagate,
|
||||
MAIL_ADDR_FORM_EXTERNAL, MAIL_ADDR_FORM_EXTERNAL)) != 0) {
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL,
|
||||
MAIL_ADDR_FORM_EXTERNAL)) != 0) {
|
||||
if (new_addr->argc > 1)
|
||||
msg_warn("multi-valued %s result for %s", maps->title, STR(addr));
|
||||
result = new_addr->argv[0];
|
||||
|
@@ -114,6 +114,8 @@ smtpd_addr_valid_test: smtpd_check smtpd_addr_valid.in smtpd_addr_valid.ref
|
||||
|
||||
# This requires that the DNS server can query porcupine.org.
|
||||
|
||||
ADDRINFO_FIX = sed 's/No address associated with hostname/hostname nor servname provided, or not known/'
|
||||
|
||||
smtpd_exp_test: smtpd_check smtpd_exp.in smtpd_exp.ref
|
||||
$(SHLIB_ENV) $(VALGRIND) ../postmap/postmap hash:smtpd_check_access
|
||||
$(SHLIB_ENV) $(VALGRIND) ./smtpd_check <smtpd_exp.in >smtpd_exp.tmp 2>&1
|
||||
@@ -122,13 +124,13 @@ smtpd_exp_test: smtpd_check smtpd_exp.in smtpd_exp.ref
|
||||
|
||||
smtpd_server_test: smtpd_check smtpd_server.in smtpd_server.ref
|
||||
$(SHLIB_ENV) $(VALGRIND) ./smtpd_check <smtpd_server.in >smtpd_server.tmp 2>&1
|
||||
diff smtpd_server.ref smtpd_server.tmp
|
||||
$(ADDRINFO_FIX) smtpd_server.tmp | diff smtpd_server.ref -
|
||||
rm -f smtpd_server.tmp smtpd_check_access.*
|
||||
|
||||
smtpd_nullmx_test: smtpd_check smtpd_nullmx.in smtpd_nullmx.ref
|
||||
$(SHLIB_ENV) $(VALGRIND) ../postmap/postmap hash:smtpd_check_access
|
||||
$(SHLIB_ENV) $(VALGRIND) ./smtpd_check <smtpd_nullmx.in >smtpd_nullmx.tmp 2>&1
|
||||
diff smtpd_nullmx.ref smtpd_nullmx.tmp
|
||||
$(ADDRINFO_FIX) smtpd_nullmx.tmp | diff smtpd_nullmx.ref -
|
||||
rm -f smtpd_nullmx.tmp smtpd_check_access.*
|
||||
|
||||
smtpd_dns_filter_test: smtpd_check smtpd_dns_filter.in smtpd_dns_filter.ref \
|
||||
|
@@ -653,6 +653,8 @@ static ARGV *smtpd_check_parse(int flags, const char *checks)
|
||||
return (argv);
|
||||
}
|
||||
|
||||
#ifndef TEST
|
||||
|
||||
/* has_required - make sure required restriction is present */
|
||||
|
||||
static int has_required(ARGV *restrictions, const char **required)
|
||||
@@ -711,6 +713,8 @@ static void fail_required(const char *name, const char **required)
|
||||
name, STR(example));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* smtpd_check_init - initialize once during process lifetime */
|
||||
|
||||
void smtpd_check_init(void)
|
||||
@@ -719,6 +723,7 @@ void smtpd_check_init(void)
|
||||
const char *name;
|
||||
const char *value;
|
||||
char *cp;
|
||||
#ifndef TEST
|
||||
static const char *rcpt_required[] = {
|
||||
REJECT_UNAUTH_DEST,
|
||||
DEFER_UNAUTH_DEST,
|
||||
@@ -728,6 +733,7 @@ void smtpd_check_init(void)
|
||||
CHECK_RELAY_DOMAINS,
|
||||
0,
|
||||
};
|
||||
#endif
|
||||
static NAME_CODE tempfail_actions[] = {
|
||||
DEFER_ALL, DEFER_ALL_ACT,
|
||||
DEFER_IF_PERMIT, DEFER_IF_PERMIT_ACT,
|
||||
@@ -3205,9 +3211,9 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
|
||||
* Look up user+foo@domain if the address has an extension, user@domain
|
||||
* otherwise.
|
||||
*/
|
||||
#define LOOKUP_STRATEGY (MAIL_ADDR_FIND_FULL | MAIL_ADDR_FIND_NOEXT \
|
||||
| MAIL_ADDR_FIND_DOMAIN | MAIL_ADDR_FIND_PMS \
|
||||
| MAIL_ADDR_FIND_LOCALPART_AT)
|
||||
#define LOOKUP_STRATEGY (MAF_STRATEGY_FULL | MAF_STRATEGY_NOEXT \
|
||||
| MAF_STRATEGY_DOMAIN | MAF_STRATEGY_PMS \
|
||||
| MAF_STRATEGY_LOCALPART_AT)
|
||||
|
||||
if ((maps = (MAPS *) htable_find(map_command_table, table)) == 0) {
|
||||
msg_warn("%s: unexpected dictionary: %s", myname, table);
|
||||
@@ -5893,7 +5899,6 @@ int main(int argc, char **argv)
|
||||
char *bp;
|
||||
char *resp;
|
||||
char *addr;
|
||||
INET_PROTO_INFO *proto_info;
|
||||
|
||||
/*
|
||||
* Initialization. Use dummies for client information.
|
||||
@@ -5905,7 +5910,7 @@ int main(int argc, char **argv)
|
||||
int_init();
|
||||
smtpd_check_init();
|
||||
smtpd_expand_init();
|
||||
proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_IPV4);
|
||||
(void) inet_proto_init(argv[0], INET_PROTO_NAME_IPV4);
|
||||
smtpd_state_init(&state, VSTREAM_IN, "smtpd");
|
||||
state.queue_id = "<queue id>";
|
||||
|
||||
|
@@ -261,9 +261,9 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr,
|
||||
* internal form.
|
||||
*/
|
||||
#define LOOKUP_STRATEGY \
|
||||
(MAIL_ADDR_FIND_FULL | MAIL_ADDR_FIND_NOEXT | MAIL_ADDR_FIND_DOMAIN | \
|
||||
(MAF_STRATEGY_FULL | MAF_STRATEGY_NOEXT | MAF_STRATEGY_DOMAIN | \
|
||||
(transport_match_parent_style == MATCH_FLAG_PARENT ? \
|
||||
MAIL_ADDR_FIND_PMS : MAIL_ADDR_FIND_PMDS))
|
||||
MAF_STRATEGY_PMS : MAF_STRATEGY_PMDS))
|
||||
|
||||
if ((ratsign = strrchr(addr, '@')) == 0 || ratsign[1] == 0)
|
||||
msg_panic("transport_lookup: bad address: \"%s\"", addr);
|
||||
@@ -427,7 +427,7 @@ int main(int argc, char **argv)
|
||||
vstring_free(nexthop);
|
||||
vstring_free(channel);
|
||||
vstring_free(buffer);
|
||||
exit(0);
|
||||
exit(errs != 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user