relocated_maps). These features may be migrated later to
enable quoted-form address lookup keys, for consistency
with other Postfix features.
+
+20170109
+
+ Cleanup: reduce the number of modified files, to make a
+ back-port more feasible. This renames foo() to foo_opt(),
+ and renames the backwards_compatibility foo_noconv() to
+ their old name foo().
Disable -DSNAPSHOT and -DNONPROD in makedefs.
- Document RFC5321 localpart quoting in DATABASE_README.
+ Document RFC5322 localpart quoting in DATABASE_README.
+
+ Add quote_822_local() flag to indicate if an address
+ is complete or localpart only. This avoids incorrect
+ results when a localpart-only input contains '@'.
In the bounce daemon, set util_utf8_enable if returning an
SMTPUTF8 message.
if ((state->flags & CLEANUP_FLAG_BCC_OK)
&& *STR(clean_addr)
&& cleanup_send_bcc_maps) {
- if ((bcc = mail_addr_find_noconv(cleanup_send_bcc_maps,
- STR(clean_addr),
- IGNORE_EXTENSION)) != 0) {
+ if ((bcc = mail_addr_find(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 -- "
if ((state->flags & CLEANUP_FLAG_BCC_OK)
&& *STR(clean_addr)
&& cleanup_rcpt_bcc_maps) {
- if ((bcc = mail_addr_find_noconv(cleanup_rcpt_bcc_maps,
- STR(clean_addr),
- IGNORE_EXTENSION)) != 0) {
+ if ((bcc = mail_addr_find(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 -- "
* the place.
*/
for (count = 0; count < MAX_RECURSION; count++) {
- if ((new_addr = mail_addr_map(maps, STR(addr), propagate,
- MAIL_ADDR_FORM_EXTERNAL,
- MAIL_ADDR_FORM_EXTERNAL)) != 0) {
+ if ((new_addr = mail_addr_map_opt(maps, STR(addr), propagate,
+ MAIL_ADDR_FORM_EXTERNAL,
+ MAIL_ADDR_FORM_EXTERNAL)) != 0) {
if (new_addr->argc > 1)
msg_warn("%s: multi-valued %s entry for %s",
state->queue_id, maps->title, STR(addr));
/* const char *string;
/* const char *extension;
/*
-/* ARGV *mail_addr_crunch(string, extension, in_form, out_form)
+/* ARGV *mail_addr_crunch_opt(string, extension, in_form, out_form)
/* const char *string;
/* const char *extension;
/* int in_form;
/* int out_form;
/* LEGACY SUPPORT
-/* ARGV *mail_addr_crunch_noconv(string, extension)
+/* ARGV *mail_addr_crunch(string, extension)
/* const char *string;
/* const char *extension;
/* DESCRIPTION
/* between internal and external forms. The caller is expected
/* to pass the result to argv_free().
/*
-/* mail_addr_crunch() gives more control, at the cost of
+/* mail_addr_crunch_opt() gives more control, at the cost of
/* additional conversions between internal and external forms.
/*
-/* mail_addr_crunch_noconv() is used by legacy code and performs
+/* mail_addr_crunch() is used by legacy code and performs
/* no conversion between internal and external forms.
/*
/* Arguments:
/* mail_addr_crunch - break string into addresses, optionally add extension */
-ARGV *mail_addr_crunch(const char *string, const char *extension,
+ARGV *mail_addr_crunch_opt(const char *string, const char *extension,
int in_form, int out_form)
{
VSTRING *intern_addr = vstring_alloc(100);
vstream_fflush(VSTREAM_OUT);
}
while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
- argv = mail_addr_crunch(STR(buf), (VSTRING_LEN(extension) ?
+ argv = mail_addr_crunch_opt(STR(buf), (VSTRING_LEN(extension) ?
STR(extension) : 0),
in_form, out_form);
for (cpp = argv->argv; *cpp; cpp++)
* Global library.
*/
#include <mail_addr_form.h>
-#include <argv.h>
/*
* External interface.
*/
-extern ARGV *mail_addr_crunch(const char *, const char *, int, int);
+extern ARGV *mail_addr_crunch_opt(const char *, const char *, int, int);
- /* The least-overhead form. */
+ /*
+ * The least-overhead form.
+ */
#define mail_addr_crunch_ext_to_int(string, extension) \
- mail_addr_crunch((string), (extension), MAIL_ADDR_FORM_EXTERNAL, \
+ mail_addr_crunch_opt((string), (extension), MAIL_ADDR_FORM_EXTERNAL, \
MAIL_ADDR_FORM_INTERNAL)
- /* The legacy form. */
-#define mail_addr_crunch_noconv(string, extension) \
- mail_addr_crunch((string), (extension), MAIL_ADDR_FORM_NOCONV, \
+ /*
+ * The legacy form.
+ */
+#define mail_addr_crunch(string, extension) \
+ mail_addr_crunch_opt((string), (extension), MAIL_ADDR_FORM_NOCONV, \
MAIL_ADDR_FORM_NOCONV)
/* LICENSE
/* const char *address;
/* char **extension;
/*
-/* const char *mail_addr_find(maps, address, extension, in_form, out_form)
+/* const char *mail_addr_find_opt(maps, address, extension,
+/* in_form, out_form)
/* MAPS *maps;
/* const char *address;
/* char **extension;
/* int in_form;
/* int out_form;
/* LEGACY SUPPORT
-/* const char *mail_addr_find_noconv(maps, address, extension)
+/* const char *mail_addr_find(maps, address, extension)
/* MAPS *maps;
/* const char *address;
/* char **extension;
/* (unquoted/quoted) conversions of the query, extension, or
/* result.
/*
-/* mail_addr_find() gives more control, at the cost of
+/* 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
/* that the lookup result is an email address.
/*
-/* mail_addr_find_noconv() is used by legacy code that is not
+/* mail_addr_find() is used by legacy code that is not
/* yet aware of internal versus external addres formats.
/*
/* mail_addr_find_trans() implements transitional functionality.
-/* It behaves like mail_addr_find(...INTERNAL, ...NOCONV) and
+/* It behaves like mail_addr_find_opt(...INTERNAL, ...NOCONV) and
/* searches a table with the quoted form of the address, but
/* if the lookup produces no result, and the quoted address
/* differs from the unquoted form, it also tries
-/* mail_addr_find(...NOCONV, ...NOCONV).
+/* mail_addr_find_opt(...NOCONV, ...NOCONV).
/*
/* An address that is in the form \fIuser\fR matches itself.
/*
static VSTRING *quoted_addr;
/*
- * First, let mail_addr_find() search with the address converted to
+ * First, let mail_addr_find_opt() search with the address converted to
* external form. Fall back to a search with the address in internal
* (unconverted) form, if no match was found and the internal and
* external forms differ.
*/
- if ((result = mail_addr_find(path, address, extp,
+ if ((result = mail_addr_find_opt(path, address, extp,
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_NOCONV)) == 0) {
if (quoted_addr == 0)
quoted_addr = vstring_alloc(100);
quote_822_local(quoted_addr, address);
if (strcmp(STR(quoted_addr), address) != 0)
- result = mail_addr_find(path, address, extp,
+ result = mail_addr_find_opt(path, address, extp,
MAIL_ADDR_FORM_NOCONV, MAIL_ADDR_FORM_NOCONV);
}
return (result);
/* mail_addr_find - map a canonical address */
-const char *mail_addr_find(MAPS *path, const char *address, char **extp,
- int in_form, int out_form)
+const char *mail_addr_find_opt(MAPS *path, const char *address, char **extp,
+ int in_form, int out_form)
{
const char *myname = "mail_addr_find";
VSTRING *ext_addr_buf = 0;
int_bare_key = saved_ext = 0;
} else {
int_bare_key =
- strip_addr_internal(int_full_key, &saved_ext, var_rcpt_delim);
+ strip_addr(int_full_key, &saved_ext, var_rcpt_delim);
}
/*
expect_res = mystrtok(&bp, ":");
expect_ext = mystrtok(&bp, ":");
extent = 0;
- result = mail_addr_find(path, key_field, &extent, in_form, out_form);
+ result = mail_addr_find_opt(path, key_field, &extent, in_form, out_form);
vstream_printf("%s:%s -> %s:%s (%s)\n",
in_field, key_field, out_field, result ? result :
path->error ? "(try again)" :
/*
* External interface.
*/
-extern const char *mail_addr_find(MAPS *, const char *, char **, int, int);
+extern const char *mail_addr_find_opt(MAPS *, const char *, char **, int, int);
+extern const char *mail_addr_find_trans(MAPS *, const char *, char **);
/* The least-overhead form. */
#define mail_addr_find_int_to_ext(maps, address, extension) \
- mail_addr_find((maps), (address), (extension), \
+ mail_addr_find_opt((maps), (address), (extension), \
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_EXTERNAL)
/* The legacy form. */
-#define mail_addr_find_noconv(maps, address, extension) \
- mail_addr_find((maps), (address), (extension), \
+#define mail_addr_find(maps, address, extension) \
+ mail_addr_find_opt((maps), (address), (extension), \
MAIL_ADDR_FORM_NOCONV, MAIL_ADDR_FORM_NOCONV)
/* LICENSE
/* const char *address;
/* int propagate;
/*
-/* ARGV *mail_addr_map(path, address, propagate, in_form, out_form)
+/* ARGV *mail_addr_map_opt(path, address, propagate, in_form, out_form)
/* MAPS *path;
/* const char *address;
/* int propagate;
/* named address, or a null pointer if none is found. The
/* search address and results are in internal (unquoted) form.
/*
-/* mail_addr_map() gives more control, at the cost of additional
+/* mail_addr_map_opt() gives more control, at the cost of additional
/* conversions between internal and external forms.
/*
/* When the \fBpropagate\fR argument is non-zero,
/* the original user in
/* \fIotherdomain\fR.
/*
-/* mail_addr_map() gives additional control over whether the
+/* 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
/* mail_addr_map - map a canonical address */
-ARGV *mail_addr_map(MAPS *path, const char *address, int propagate,
- int in_form, int out_form)
+ARGV *mail_addr_map_opt(MAPS *path, const char *address, int propagate,
+ int in_form, int out_form)
{
VSTRING *buffer = 0;
const char *myname = "mail_addr_map";
/*
* Optionally convert input from external form. We prefer internal-form
- * input to avoid an unnecessary input conversion in mail_addr_find().
- * 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 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.
*/
if (in_form == MAIL_ADDR_FORM_EXTERNAL) {
int_address = vstring_alloc(100);
/*
* 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() variant that does not convert
- * the lookup result.
+ * We explicitly call the mail_addr_find_opt() variant that does not
+ * convert the lookup result.
*/
- if ((string = mail_addr_find(path, int_addr, &extension,
- in_form, mid_form)) != 0) {
+ if ((string = mail_addr_find_opt(path, int_addr, &extension,
+ in_form, mid_form)) != 0) {
/*
* Prepend the original user to @otherdomain, but do not propagate
* Canonicalize the result, and propagate the unmatched extension to
* each address found.
*/
- argv = mail_addr_crunch(string, propagate ? extension : 0,
- mid_form, out_form);
+ argv = mail_addr_crunch_opt(string, propagate ? extension : 0,
+ mid_form, out_form);
if (buffer)
vstring_free(buffer);
if (ext_address)
/*
* External interface.
*/
-extern ARGV *mail_addr_map(MAPS *, const char *, int, int, int);
+extern ARGV *mail_addr_map_opt(MAPS *, const char *, int, int, int);
/* The least-overhead form. */
#define mail_addr_map_internal(path, address, propagate) \
- mail_addr_map((path), (address), (propagate), \
+ mail_addr_map_opt((path), (address), (propagate), \
MAIL_ADDR_FORM_INTERNAL, MAIL_ADDR_FORM_INTERNAL)
/* LICENSE
#define PLUS_RECIPIENT_DELIMITER "+"
/*
- * All these tests must pass, so that we know that mail_addr_map() works as
- * intended.
+ * All these tests must pass, so that we know that mail_addr_map_opt() works
+ * as intended.
*/
static MAIL_ADDR_MAP_TEST pass_tests[] = {
{
| DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
UPDATE(var_rcpt_delim, test->delimiter);
- result = mail_addr_map(maps, test->address, test->propagate,
- test->in_form, test->out_form);
+ 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);
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20170108"
+#define MAIL_RELEASE_DATE "20170109"
#define MAIL_VERSION_NUMBER "3.2"
#ifdef SNAPSHOT
/* found, and returns a pointer to the remainder. The address
/* must be in internal (unquoted) form.
/*
+/* split_addr() is a backwards-compatible form for legacy code.
+/* It is an alias for split_addr_internal().
+/*
/* Reserved addresses are not split: postmaster, mailer-daemon,
/* double-bounce. Addresses that begin with owner-, or addresses
/* that end in -request are not split when the owner_request_special
extern char *split_addr_internal(char *, const char *);
+ /* Legacy API. */
+
+#define split_addr split_addr_internal
+
/* LICENSE
/* .ad
/* .fi
/* The caller is expected to pass the copy to myfree().
/* The input and result are in internal form.
/*
+/* strip_addr() is a backwards-compatible form for legacy code.
+/* It is an alias for strip_addr_internal().
+/*
/* Arguments:
/* .IP address
/* Address localpart or user@domain form in internal form.
stripped = mystrdup(full);
if ((ratsign = strrchr(stripped, '@')) != 0)
*ratsign = 0;
- if ((extent = split_addr_internal(stripped, delimiter_set)) != 0) {
+ if ((extent = split_addr(stripped, delimiter_set)) != 0) {
extent -= 1;
if (extension) {
*extent = full[strlen(stripped)];
/* DESCRIPTION
/* .nf
- /*
- * External interface.
- */
-extern char * strip_addr_internal(const char *, char **, const char *);
+ /* External interface. */
+
+extern char *strip_addr_internal(const char *, char **, const char *);
+
+#define strip_addr strip_addr_internal
/* LICENSE
/* .ad
FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
if (alias_maps->error == 0 && owner_expansion == 0
- && (stripped_recipient =
- strip_addr_internal(state.msg_attr.rcpt.address,
- (char **) 0,
- var_rcpt_delim)) != 0) {
+ && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
+ (char **) 0,
+ var_rcpt_delim)) != 0) {
myfree(owner_alias);
FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
myfree(stripped_recipient);
state.msg_attr.user = mystrdup(state.msg_attr.local);
if (*var_rcpt_delim) {
state.msg_attr.extension =
- split_addr_internal(state.msg_attr.user, var_rcpt_delim);
+ split_addr(state.msg_attr.user, var_rcpt_delim);
if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
msg_warn("%s: address with illegal extension: %s",
state.msg_attr.queue_id, state.msg_attr.local);
: strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */
- if (*var_rcpt_delim
- && split_addr_internal(STR(queue_name), var_rcpt_delim))
+ if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address);
if (*var_rcpt_delim)
- split_addr_internal(STR(buf), var_rcpt_delim);
+ split_addr(STR(buf), var_rcpt_delim);
if (*STR(buf) == 0)
continue;
dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address);
if (*var_rcpt_delim == 0
- || (ext = split_addr_internal(STR(buf),
- var_rcpt_delim)) == 0)
+ || (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
ext = ""; /* insert null arg */
dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
}
: strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */
- if (*var_rcpt_delim
- && split_addr_internal(STR(queue_name), var_rcpt_delim))
+ if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
ARGV *new_addr;
const char *result;
- if ((new_addr = mail_addr_map(maps, STR(addr), propagate,
+ if ((new_addr = mail_addr_map_opt(maps, STR(addr), propagate,
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));
#include <ehlo_mask.h>
#include <maps.h>
#include <tok822.h>
+#include <mail_addr_map.h>
#include <ext_prop.h>
#include <namadr_list.h>
#include <match_parent_style.h>
smtp_sasl_passwd_map->error = 0;
if ((smtp_mode
&& var_smtp_sender_auth && state->request->sender[0]
- && (value = mail_addr_find_noconv(smtp_sasl_passwd_map,
+ && (value = mail_addr_find(smtp_sasl_passwd_map,
state->request->sender, (char **) 0)) != 0)
|| (smtp_sasl_passwd_map->error == 0
&& (value = maps_find(smtp_sasl_passwd_map,
{
const char *result;
- if ((result = mail_addr_find_noconv(maps, key, ext)) != 0
- || maps->error == 0)
+ if ((result = mail_addr_find(maps, key, ext)) != 0 || maps->error == 0)
return (result);
if (maps->error == DICT_ERR_RETRY)
/* Warning is already logged. */
if (*var_rcpt_delim == 0) {
bare_addr = 0;
} else {
- bare_addr = strip_addr_internal(addr, (char **) 0, var_rcpt_delim);
+ bare_addr = strip_addr(addr, (char **) 0, var_rcpt_delim);
}
#define CHECK_MAIL_ACCESS_RETURN(x) \
* Search the recipient lookup tables of the respective address class.
*
* XXX Use the less expensive maps_find() (built-in case folding) instead of
- * the baroque mail_addr_find(). But then we have to strip the domain and
- * deal with address extensions ourselves.
+ * the baroque mail_addr_find(). But then we have to strip the domain
+ * and deal with address extensions ourselves.
*
* XXX But that would break sites that use the virtual delivery agent for
* local delivery, because the virtual delivery agent requires
*/
else {
if (rp->snd_def_xp_info
- && (xport = mail_addr_find_noconv(rp->snd_def_xp_info,
+ && (xport = mail_addr_find(rp->snd_def_xp_info,
sender_key = (*sender ? sender :
var_null_def_xport_maps_key),
- (char **) 0)) != 0) {
+ (char **) 0)) != 0) {
if (*xport == 0) {
msg_warn("%s: ignoring null lookup result for %s",
rp->snd_def_xp_maps_name, sender_key);
* override the recipient domain.
*/
if (rp->snd_relay_info
- && (relay = mail_addr_find_noconv(rp->snd_relay_info,
- sender_key = (*sender ? sender :
+ && (relay = mail_addr_find(rp->snd_relay_info,
+ sender_key = (*sender ? sender :
var_null_relay_maps_key),
- (char **) 0)) != 0) {
+ (char **) 0)) != 0) {
if (*relay == 0) {
msg_warn("%s: ignoring null lookup result for %s",
rp->snd_relay_maps_name, sender_key);
if (relocated_maps != 0) {
const char *newloc;
- if ((newloc = mail_addr_find_noconv(relocated_maps, STR(nextrcpt),
- IGNORE_ADDR_EXTENSION)) != 0) {
+ if ((newloc = mail_addr_find(relocated_maps, STR(nextrcpt),
+ IGNORE_ADDR_EXTENSION)) != 0) {
vstring_strcpy(channel, MAIL_SERVICE_ERROR);
/* 5.1.6 is the closest match, but not perfect. */
vstring_sprintf(nexthop, "5.1.6 User has moved to %s", newloc);
* look up the stripped address with the PARTIAL flag to avoid matching
* partial lookup keys with regular expressions.
*/
- if ((stripped_addr = strip_addr_internal(addr, DISCARD_EXTENSION,
- var_rcpt_delim)) != 0) {
+ if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION,
+ var_rcpt_delim)) != 0) {
found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
channel, nexthop);
*/
#define IGNORE_EXTENSION ((char **) 0)
- mailbox_res = mail_addr_find_noconv(virtual_mailbox_maps,
- state.msg_attr.user,
- IGNORE_EXTENSION);
+ mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user,
+ IGNORE_EXTENSION);
if (mailbox_res == 0) {
if (virtual_mailbox_maps->error == 0)
return (NO);
/*
* Look up the mailbox owner rights. Defer in case of trouble.
*/
- uid_res = mail_addr_find_noconv(virtual_uid_maps, state.msg_attr.user,
- IGNORE_EXTENSION);
+ uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
+ IGNORE_EXTENSION);
if (uid_res == 0) {
msg_warn("recipient %s: not found in %s",
state.msg_attr.user, virtual_uid_maps->title);
/*
* Look up the mailbox group rights. Defer in case of trouble.
*/
- gid_res = mail_addr_find_noconv(virtual_gid_maps, state.msg_attr.user,
- IGNORE_EXTENSION);
+ gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
+ IGNORE_EXTENSION);
if (gid_res == 0) {
msg_warn("recipient %s: not found in %s",
state.msg_attr.user, virtual_gid_maps->title);