/* $NetBSD: mail_addr_find.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */
/*++
/* NAME
/* mail_addr_find 3
/* SUMMARY
/* generic address-based lookup
/* SYNOPSIS
/* #include <mail_addr_find.h>
/*
/* const char *mail_addr_find(maps, address, extension)
/* MAPS *maps;
/* const char *address;
/* char **extension;
/* DESCRIPTION
/* mail_addr_find() searches the specified maps for an entry with as
/* key the specified address, and derivations from that address.
/* It is up to the caller to specify its case sensitivity
/* preferences when it opens the maps.
/* The result is overwritten upon each call.
/*
/* An address that is in the form \fIuser\fR matches itself.
/*
/* Given an address of the form \fIuser@domain\fR, the following
/* lookups are done in the given order until one returns a result:
/* .IP user@domain
/* Look up the entire address.
/* .IP user
/* Look up \fIuser\fR when \fIdomain\fR is equal to $myorigin,
/* when \fIdomain\fR matches $mydestination, or when it matches
/* $inet_interfaces or $proxy_interfaces.
/* .IP @domain
/* Look for an entry that matches the domain specified in \fIaddress\fR.
/* .PP
/* With address extension enabled, the table lookup order is:
/* \fIuser+extension\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR,
/* \fIuser+extension\fR, \fIuser\fR, and @\fIdomain\fR.
/* .PP
/* Arguments:
/* .IP maps
/* Dictionary search path (see maps(3)).
/* .IP address
/* The address to be looked up.
/* .IP extension
/* A null pointer, or the address of a pointer that is set to
/* the address of a dynamic memory copy of the address extension
/* that had to be chopped off in order to match the lookup tables.
/* The copy includes the recipient address delimiter.
/* The caller is expected to pass the copy to myfree().
/* DIAGNOSTICS
/* 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
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
/* Utility library. */
#include <msg.h>
#include <dict.h>
#include <stringops.h>
#include <mymalloc.h>
#include <vstring.h>
/* Global library. */
#include <mail_params.h>
#include <strip_addr.h>
#include <mail_addr_find.h>
#include <resolve_local.h>
/* Application-specific. */
#define STR vstring_str
/* mail_addr_find - map a canonical address */
const char *mail_addr_find(MAPS *path, const char *address, char **extp)
{
const char *myname = "mail_addr_find";
const char *result;
char *ratsign = 0;
char *full_key;
char *bare_key;
char *saved_ext;
int rc = 0;
/*
* Initialize.
*/
full_key = mystrdup(address);
if (*var_rcpt_delim == 0) {
bare_key = saved_ext = 0;
} else {
bare_key = strip_addr(full_key, &saved_ext, var_rcpt_delim);
}
/*
* Try user+foo@domain and user@domain.
*
* Specify what keys are partial or full, to avoid matching partial
* addresses with regular expressions.
*/
#define FULL 0
#define PARTIAL DICT_FLAG_FIXED
if ((result = maps_find(path, full_key, FULL)) == 0 && path->error == 0
&& bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0
&& extp != 0) {
*extp = saved_ext;
saved_ext = 0;
}
/*
* Try 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(full_key, '@')) != 0
&& (strcasecmp_utf8(ratsign + 1, var_myorigin) == 0
|| (rc = resolve_local(ratsign + 1)) > 0)) {
*ratsign = 0;
result = maps_find(path, full_key, PARTIAL);
if (result == 0 && path->error == 0 && bare_key != 0) {
if ((ratsign = strrchr(bare_key, '@')) == 0)
msg_panic("%s: bare key botch", myname);
*ratsign = 0;
if ((result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) {
*extp = saved_ext;
saved_ext = 0;
}
}
*ratsign = '@';
} else if (rc < 0)
path->error = rc;
/*
* Try @domain.
*/
if (result == 0 && path->error == 0 && ratsign)
result = maps_find(path, ratsign, PARTIAL);
/*
* Clean up.
*/
if (msg_verbose)
msg_info("%s: %s -> %s", myname, address,
result ? result :
path->error ? "(try again)" :
"(not found)");
myfree(full_key);
if (bare_key)
myfree(bare_key);
if (saved_ext)
myfree(saved_ext);
return (result);
}
#ifdef TEST
/*
* Proof-of-concept test program. Read an address from stdin, and spit out
* the lookup result.
*/
#include <vstream.h>
#include <vstring_vstream.h>
#include <mail_conf.h>
int main(int argc, char **argv)
{
VSTRING *buffer = vstring_alloc(100);
MAPS *path;
const char *result;
char *extent;
/*
* Parse JCL.
*/
if (argc != 2)
msg_fatal("usage: %s database", argv[0]);
msg_verbose = 1;
/*
* Initialize.
*/
mail_conf_read();
path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX \
|DICT_FLAG_UTF8_REQUEST);
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
extent = 0;
result = mail_addr_find(path, STR(buffer), &extent);
vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result :
path->error ? "(try again)" :
"(not found)", extent ? extent : "null extension");
vstream_fflush(VSTREAM_OUT);
if (extent)
myfree(extent);
}
vstring_free(buffer);
maps_free(path);
return (0);
}
#endif