Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / rewrite_clnt.c
blob3325c637c13a6fea607a329c3a3561fe35a246fd
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* rewrite_clnt 3
6 /* SUMMARY
7 /* address rewrite service client
8 /* SYNOPSIS
9 /* #include <vstring.h>
10 /* #include <rewrite_clnt.h>
12 /* VSTRING *rewrite_clnt(ruleset, address, result)
13 /* const char *ruleset;
14 /* const char *address;
16 /* VSTRING *rewrite_clnt_internal(ruleset, address, result)
17 /* const char *ruleset;
18 /* const char *address;
19 /* VSTRING *result;
20 /* DESCRIPTION
21 /* This module implements a mail address rewriting client.
23 /* rewrite_clnt() sends a rule set name and external-form address to the
24 /* rewriting service and returns the resulting external-form address.
25 /* In case of communication failure the program keeps trying until the
26 /* mail system shuts down.
28 /* rewrite_clnt_internal() performs the same functionality but takes
29 /* input in internal (unquoted) form, and produces output in internal
30 /* (unquoted) form.
31 /* DIAGNOSTICS
32 /* Warnings: communication failure. Fatal error: mail system is down.
33 /* SEE ALSO
34 /* mail_proto(3h) low-level mail component glue.
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /* The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*--*/
46 /* System library. */
48 #include <sys_defs.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <string.h>
53 /* Utility library. */
55 #include <msg.h>
56 #include <vstring.h>
57 #include <vstream.h>
58 #include <vstring_vstream.h>
59 #include <events.h>
60 #include <iostuff.h>
61 #include <quote_822_local.h>
63 /* Global library. */
65 #include "mail_proto.h"
66 #include "mail_params.h"
67 #include "clnt_stream.h"
68 #include "rewrite_clnt.h"
70 /* Application-specific. */
73 * XXX this is shared with the resolver client to save a file descriptor.
75 CLNT_STREAM *rewrite_clnt_stream = 0;
77 static time_t last_expire;
78 static VSTRING *last_rule;
79 static VSTRING *last_addr;
80 static VSTRING *last_result;
82 /* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
84 VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
86 VSTREAM *stream;
87 int server_flags;
88 int count = 0;
91 * One-entry cache.
93 if (last_addr == 0) {
94 last_rule = vstring_alloc(10);
95 last_addr = vstring_alloc(100);
96 last_result = vstring_alloc(100);
100 * Sanity check. An address must be in externalized form. The result must
101 * not clobber the input, because we may have to retransmit the query.
103 #define STR vstring_str
105 if (*addr == 0)
106 addr = "";
107 if (addr == STR(result))
108 msg_panic("rewrite_clnt: result clobbers input");
111 * Peek at the cache.
113 if (time((time_t *) 0) < last_expire
114 && strcmp(addr, STR(last_addr)) == 0
115 && strcmp(rule, STR(last_rule)) == 0) {
116 vstring_strcpy(result, STR(last_result));
117 if (msg_verbose)
118 msg_info("rewrite_clnt: cached: %s: %s -> %s",
119 rule, addr, vstring_str(result));
120 return (result);
124 * Keep trying until we get a complete response. The rewrite service is
125 * CPU bound and making the client asynchronous would just complicate the
126 * code.
128 if (rewrite_clnt_stream == 0)
129 rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
130 var_rewrite_service,
131 var_ipc_idle_limit,
132 var_ipc_ttl_limit);
134 for (;;) {
135 stream = clnt_stream_access(rewrite_clnt_stream);
136 errno = 0;
137 count += 1;
138 if (attr_print(stream, ATTR_FLAG_NONE,
139 ATTR_TYPE_STR, MAIL_ATTR_REQ, REWRITE_ADDR,
140 ATTR_TYPE_STR, MAIL_ATTR_RULE, rule,
141 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
142 ATTR_TYPE_END) != 0
143 || vstream_fflush(stream)
144 || attr_scan(stream, ATTR_FLAG_STRICT,
145 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags,
146 ATTR_TYPE_STR, MAIL_ATTR_ADDR, result,
147 ATTR_TYPE_END) != 2) {
148 if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
149 msg_warn("problem talking to service %s: %m",
150 var_rewrite_service);
151 } else {
152 if (msg_verbose)
153 msg_info("rewrite_clnt: %s: %s -> %s",
154 rule, addr, vstring_str(result));
155 /* Server-requested disconnect. */
156 if (server_flags != 0)
157 clnt_stream_recover(rewrite_clnt_stream);
158 break;
160 sleep(1); /* XXX make configurable */
161 clnt_stream_recover(rewrite_clnt_stream);
165 * Update the cache.
167 vstring_strcpy(last_rule, rule);
168 vstring_strcpy(last_addr, addr);
169 vstring_strcpy(last_result, STR(result));
170 last_expire = time((time_t *) 0) + 30; /* XXX make configurable */
172 return (result);
175 /* rewrite_clnt_internal - rewrite from/to internal form */
177 VSTRING *rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
179 VSTRING *src = vstring_alloc(100);
180 VSTRING *dst = vstring_alloc(100);
183 * Convert the address from internal address form to external RFC822
184 * form, then rewrite it. After rewriting, convert to internal form.
186 quote_822_local(src, addr);
187 rewrite_clnt(ruleset, STR(src), dst);
188 unquote_822_local(result, STR(dst));
189 vstring_free(src);
190 vstring_free(dst);
191 return (result);
194 #ifdef TEST
196 #include <stdlib.h>
197 #include <string.h>
198 #include <msg_vstream.h>
199 #include <split_at.h>
200 #include <vstring_vstream.h>
201 #include <mail_conf.h>
202 #include <mail_params.h>
204 static NORETURN usage(char *myname)
206 msg_fatal("usage: %s [-v] [rule address...]", myname);
209 static void rewrite(char *rule, char *addr, VSTRING *reply)
211 rewrite_clnt(rule, addr, reply);
212 vstream_printf("%-10s %s\n", "rule", rule);
213 vstream_printf("%-10s %s\n", "address", addr);
214 vstream_printf("%-10s %s\n\n", "result", STR(reply));
215 vstream_fflush(VSTREAM_OUT);
218 int main(int argc, char **argv)
220 VSTRING *reply;
221 int ch;
222 char *rule;
223 char *addr;
225 msg_vstream_init(argv[0], VSTREAM_ERR);
227 mail_conf_read();
228 msg_info("using config files in %s", var_config_dir);
229 if (chdir(var_queue_dir) < 0)
230 msg_fatal("chdir %s: %m", var_queue_dir);
232 while ((ch = GETOPT(argc, argv, "v")) > 0) {
233 switch (ch) {
234 case 'v':
235 msg_verbose++;
236 break;
237 default:
238 usage(argv[0]);
241 reply = vstring_alloc(1);
243 if (argc > optind) {
244 for (;;) {
245 if ((rule = argv[optind++]) == 0)
246 break;
247 if ((addr = argv[optind++]) == 0)
248 usage(argv[0]);
249 rewrite(rule, addr, reply);
251 } else {
252 VSTRING *buffer = vstring_alloc(1);
254 while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
255 if ((addr = split_at(STR(buffer), ' ')) == 0
256 || *(rule = STR(buffer)) == 0)
257 usage(argv[0]);
258 rewrite(rule, addr, reply);
260 vstring_free(buffer);
262 vstring_free(reply);
263 exit(0);
266 #endif