Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / trivial-rewrite / rewrite.c
blob52f5a33d962f99da4ceae47424cebba5067a6aa4
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* rewrite 3
6 /* SUMMARY
7 /* mail address rewriter
8 /* SYNOPSIS
9 /* #include "trivial-rewrite.h"
11 /* void rewrite_init(void)
13 /* void rewrite_proto(stream)
14 /* VSTREAM *stream;
16 /* void rewrite_addr(context, addr, result)
17 /* RWR_CONTEXT *context;
18 /* char *addr;
19 /* VSTRING *result;
21 /* void rewrite_tree(context, tree)
22 /* RWR_CONTEXT *context;
23 /* TOK822 *tree;
25 /* RWR_CONTEXT local_context;
26 /* RWR_CONTEXT remote_context;
27 /* DESCRIPTION
28 /* This module implements the trivial address rewriting engine.
30 /* rewrite_init() initializes data structures that are private
31 /* to this module. It should be called once before using the
32 /* actual rewriting routines.
34 /* rewrite_proto() implements the client-server protocol: read
35 /* one rule set name and one address in external (quoted) form,
36 /* reply with the rewritten address in external form.
38 /* rewrite_addr() rewrites an address string to another string.
39 /* Both input and output are in external (quoted) form.
41 /* rewrite_tree() rewrites a parse tree with a single address to
42 /* another tree. A tree is a dummy node on top of a token list.
44 /* local_context and remote_context provide domain names for
45 /* completing incomplete address forms.
46 /* STANDARDS
47 /* DIAGNOSTICS
48 /* Problems and transactions are logged to the syslog daemon.
49 /* BUGS
50 /* SEE ALSO
51 /* LICENSE
52 /* .ad
53 /* .fi
54 /* The Secure Mailer license must be distributed with this software.
55 /* AUTHOR(S)
56 /* Wietse Venema
57 /* IBM T.J. Watson Research
58 /* P.O. Box 704
59 /* Yorktown Heights, NY 10598, USA
60 /*--*/
62 /* System library. */
64 #include <sys_defs.h>
65 #include <stdlib.h>
66 #include <string.h>
68 /* Utility library. */
70 #include <msg.h>
71 #include <vstring.h>
72 #include <vstream.h>
73 #include <vstring_vstream.h>
74 #include <split_at.h>
76 /* Global library. */
78 #include <mail_params.h>
79 #include <mail_proto.h>
80 #include <resolve_local.h>
81 #include <tok822.h>
82 #include <mail_conf.h>
84 /* Application-specific. */
86 #include "trivial-rewrite.h"
88 RWR_CONTEXT local_context = {
89 VAR_MYORIGIN, &var_myorigin,
90 VAR_MYDOMAIN, &var_mydomain,
93 RWR_CONTEXT remote_context = {
94 VAR_REM_RWR_DOMAIN, &var_remote_rwr_domain,
95 VAR_REM_RWR_DOMAIN, &var_remote_rwr_domain,
98 static VSTRING *ruleset;
99 static VSTRING *address;
100 static VSTRING *result;
102 /* rewrite_tree - rewrite address according to rule set */
104 void rewrite_tree(RWR_CONTEXT *context, TOK822 *tree)
106 TOK822 *colon;
107 TOK822 *domain;
108 TOK822 *bang;
109 TOK822 *local;
112 * XXX If you change this module, quote_822_local.c, or tok822_parse.c,
113 * be sure to re-run the tests under "make rewrite_clnt_test" and "make
114 * resolve_clnt_test" in the global directory.
118 * Sanity check.
120 if (tree->head == 0)
121 msg_panic("rewrite_tree: empty tree");
124 * An empty address is a special case.
126 if (tree->head == tree->tail
127 && tree->tail->type == TOK822_QSTRING
128 && VSTRING_LEN(tree->tail->vstr) == 0)
129 return;
132 * Treat a lone @ as if it were an empty address.
134 if (tree->head == tree->tail
135 && tree->tail->type == '@') {
136 tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
137 tok822_sub_append(tree, tok822_alloc(TOK822_QSTRING, ""));
138 return;
142 * Strip source route.
144 if (tree->head->type == '@'
145 && (colon = tok822_find_type(tree->head, ':')) != 0
146 && colon != tree->tail)
147 tok822_free_tree(tok822_sub_keep_after(tree, colon));
150 * Optionally, transform address forms without @.
152 if ((domain = tok822_rfind_type(tree->tail, '@')) == 0) {
155 * Swap domain!user to user@domain.
157 if (var_swap_bangpath != 0
158 && (bang = tok822_find_type(tree->head, '!')) != 0) {
159 tok822_sub_keep_before(tree, bang);
160 local = tok822_cut_after(bang);
161 tok822_free(bang);
162 tok822_sub_prepend(tree, tok822_alloc('@', (char *) 0));
163 if (local)
164 tok822_sub_prepend(tree, local);
168 * Promote user%domain to user@domain.
170 else if (var_percent_hack != 0
171 && (domain = tok822_rfind_type(tree->tail, '%')) != 0) {
172 domain->type = '@';
176 * Append missing @origin
178 else if (var_append_at_myorigin != 0
179 && REW_PARAM_VALUE(context->origin) != 0
180 && REW_PARAM_VALUE(context->origin)[0] != 0) {
181 domain = tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
182 tok822_sub_append(tree, tok822_scan(REW_PARAM_VALUE(context->origin),
183 (TOK822 **) 0));
188 * Append missing .domain, but leave broken forms ending in @ alone. This
189 * merely makes diagnostics more accurate by leaving bogus addresses
190 * alone.
192 if (var_append_dot_mydomain != 0
193 && REW_PARAM_VALUE(context->domain) != 0
194 && REW_PARAM_VALUE(context->domain)[0] != 0
195 && (domain = tok822_rfind_type(tree->tail, '@')) != 0
196 && domain != tree->tail
197 && tok822_find_type(domain, TOK822_DOMLIT) == 0
198 && tok822_find_type(domain, '.') == 0) {
199 tok822_sub_append(tree, tok822_alloc('.', (char *) 0));
200 tok822_sub_append(tree, tok822_scan(REW_PARAM_VALUE(context->domain),
201 (TOK822 **) 0));
205 * Strip trailing dot at end of domain, but not dot-dot or @-dot. This
206 * merely makes diagnostics more accurate by leaving bogus addresses
207 * alone.
209 if (tree->tail->type == '.'
210 && tree->tail->prev
211 && tree->tail->prev->type != '.'
212 && tree->tail->prev->type != '@')
213 tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
216 /* rewrite_proto - read request and send reply */
218 int rewrite_proto(VSTREAM *stream)
220 RWR_CONTEXT *context;
221 TOK822 *tree;
223 if (attr_scan(stream, ATTR_FLAG_STRICT,
224 ATTR_TYPE_STR, MAIL_ATTR_RULE, ruleset,
225 ATTR_TYPE_STR, MAIL_ATTR_ADDR, address,
226 ATTR_TYPE_END) != 2)
227 return (-1);
229 if (strcmp(vstring_str(ruleset), MAIL_ATTR_RWR_LOCAL) == 0)
230 context = &local_context;
231 else if (strcmp(vstring_str(ruleset), MAIL_ATTR_RWR_REMOTE) == 0)
232 context = &remote_context;
233 else {
234 msg_warn("unknown context: %s", vstring_str(ruleset));
235 return (-1);
239 * Sanity check. An address is supposed to be in externalized form.
241 if (*vstring_str(address) == 0) {
242 msg_warn("rewrite_addr: null address");
243 vstring_strcpy(result, vstring_str(address));
247 * Convert the address from externalized (quoted) form to token list,
248 * rewrite it, and convert back.
250 else {
251 tree = tok822_scan_addr(vstring_str(address));
252 rewrite_tree(context, tree);
253 tok822_externalize(result, tree, TOK822_STR_DEFL);
254 tok822_free_tree(tree);
256 if (msg_verbose)
257 msg_info("`%s' `%s' -> `%s'", vstring_str(ruleset),
258 vstring_str(address), vstring_str(result));
260 attr_print(stream, ATTR_FLAG_NONE,
261 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, server_flags,
262 ATTR_TYPE_STR, MAIL_ATTR_ADDR, vstring_str(result),
263 ATTR_TYPE_END);
265 if (vstream_fflush(stream) != 0) {
266 msg_warn("write rewrite reply: %m");
267 return (-1);
269 return (0);
272 /* rewrite_init - module initializations */
274 void rewrite_init(void)
276 ruleset = vstring_alloc(100);
277 address = vstring_alloc(100);
278 result = vstring_alloc(100);