1/*++
2/* NAME
3/*	mail_addr_map 3
4/* SUMMARY
5/*	generic address mapping
6/* SYNOPSIS
7/*	#include <mail_addr_map.h>
8/*
9/*	ARGV	*mail_addr_map(path, address, propagate)
10/*	MAPS	*path;
11/*	const char *address;
12/*	int	propagate;
13/* DESCRIPTION
14/*	mail_addr_map() returns the translation for the named address,
15/*	or a null pointer if none is found.  The result is in canonical
16/*	external (quoted) form.  The search is case insensitive.
17/*
18/*	When the \fBpropagate\fR argument is non-zero,
19/*	address extensions that aren't explicitly matched in the lookup
20/*	table are propagated to the result addresses. The caller is
21/*	expected to pass the result to argv_free().
22/*
23/*	Lookups are performed by mail_addr_find(). When the result has the
24/*	form \fI@otherdomain\fR, the result is the original user in
25/*	\fIotherdomain\fR.
26/*
27/*	Arguments:
28/* .IP path
29/*	Dictionary search path (see maps(3)).
30/* .IP address
31/*	The address to be looked up.
32/* DIAGNOSTICS
33/*	Warnings: map lookup returns a non-address result.
34/*
35/*	The path->error value is non-zero when the lookup
36/*	should be tried again.
37/* SEE ALSO
38/*	mail_addr_find(3), mail address matching
39/*	mail_addr_crunch(3), mail address parsing and rewriting
40/* LICENSE
41/* .ad
42/* .fi
43/*	The Secure Mailer license must be distributed with this software.
44/* AUTHOR(S)
45/*	Wietse Venema
46/*	IBM T.J. Watson Research
47/*	P.O. Box 704
48/*	Yorktown Heights, NY 10598, USA
49/*--*/
50
51/* System library. */
52
53#include <sys_defs.h>
54#include <string.h>
55
56/* Utility library. */
57
58#include <msg.h>
59#include <vstring.h>
60#include <dict.h>
61#include <argv.h>
62#include <mymalloc.h>
63
64/* Global library. */
65
66#include <mail_addr_find.h>
67#include <mail_addr_crunch.h>
68#include <mail_addr_map.h>
69
70/* Application-specific. */
71
72#define STR	vstring_str
73#define LEN	VSTRING_LEN
74
75/* mail_addr_map - map a canonical address */
76
77ARGV   *mail_addr_map(MAPS *path, const char *address, int propagate)
78{
79    VSTRING *buffer = 0;
80    const char *myname = "mail_addr_map";
81    const char *string;
82    char   *ratsign;
83    char   *extension = 0;
84    ARGV   *argv = 0;
85    int     i;
86
87    /*
88     * Look up the full address; if no match is found, look up the address
89     * with the extension stripped off, and remember the unmatched extension.
90     */
91    if ((string = mail_addr_find(path, address, &extension)) != 0) {
92
93	/*
94	 * Prepend the original user to @otherdomain, but do not propagate
95	 * the unmatched address extension.
96	 */
97	if (*string == '@') {
98	    buffer = vstring_alloc(100);
99	    if ((ratsign = strrchr(address, '@')) != 0)
100		vstring_strncpy(buffer, address, ratsign - address);
101	    else
102		vstring_strcpy(buffer, address);
103	    if (extension)
104		vstring_truncate(buffer, LEN(buffer) - strlen(extension));
105	    vstring_strcat(buffer, string);
106	    string = STR(buffer);
107	}
108
109	/*
110	 * Canonicalize and externalize the result, and propagate the
111	 * unmatched extension to each address found.
112	 */
113	argv = mail_addr_crunch(string, propagate ? extension : 0);
114	if (buffer)
115	    vstring_free(buffer);
116	if (msg_verbose)
117	    for (i = 0; i < argv->argc; i++)
118		msg_info("%s: %s -> %d: %s", myname, address, i, argv->argv[i]);
119	if (argv->argc == 0) {
120	    msg_warn("%s lookup of %s returns non-address result \"%s\"",
121		     path->title, address, string);
122	    argv = argv_free(argv);
123	    path->error = DICT_ERR_RETRY;
124	}
125    }
126
127    /*
128     * No match found.
129     */
130    else {
131	if (msg_verbose)
132	    msg_info("%s: %s -> %s", myname, address,
133		     path->error ? "(try again)" : "(not found)");
134    }
135
136    /*
137     * Cleanup.
138     */
139    if (extension)
140	myfree(extension);
141
142    return (argv);
143}
144
145#ifdef TEST
146
147 /*
148  * Proof-of-concept test program. Read an address from stdin, and spit out
149  * the lookup result.
150  */
151#include <unistd.h>
152#include <mail_conf.h>
153#include <vstream.h>
154#include <vstring_vstream.h>
155#include <mail_params.h>
156
157int     main(int argc, char **argv)
158{
159    VSTRING *buffer = vstring_alloc(100);
160    MAPS   *path;
161    ARGV   *result;
162
163    /*
164     * Parse JCL.
165     */
166    if (argc != 2)
167	msg_fatal("usage: %s database", argv[0]);
168
169    /*
170     * Initialize.
171     */
172#define UPDATE(dst, src) { myfree(dst); dst = mystrdup(src); }
173
174    mail_conf_read();
175    msg_verbose = 1;
176    if (chdir(var_queue_dir) < 0)
177	msg_fatal("chdir %s: %m", var_queue_dir);
178    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
179    while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
180	msg_info("=== Address extension on, extension propagation on ===");
181	UPDATE(var_rcpt_delim, "+");
182	if ((result = mail_addr_map(path, STR(buffer), 1)) != 0)
183	    argv_free(result);
184	msg_info("=== Address extension on, extension propagation off ===");
185	if ((result = mail_addr_map(path, STR(buffer), 0)) != 0)
186	    argv_free(result);
187	msg_info("=== Address extension off ===");
188	UPDATE(var_rcpt_delim, "");
189	if ((result = mail_addr_map(path, STR(buffer), 1)) != 0)
190	    argv_free(result);
191    }
192    vstring_free(buffer);
193    maps_free(path);
194    return (0);
195}
196
197#endif
198