Postfix3.3.1
mail_addr_crunch.c
[詳解]
1 /*++
2 /* NAME
3 /* mail_addr_crunch 3
4 /* SUMMARY
5 /* parse and canonicalize addresses, apply address extension
6 /* SYNOPSIS
7 /* #include <mail_addr_crunch.h>
8 /*
9 /* ARGV *mail_addr_crunch_ext_to_int(string, extension)
10 /* const char *string;
11 /* const char *extension;
12 /*
13 /* ARGV *mail_addr_crunch_opt(string, extension, in_form, out_form)
14 /* const char *string;
15 /* const char *extension;
16 /* int in_form;
17 /* int out_form;
18 /* DESCRIPTION
19 /* mail_addr_crunch_*() parses a string with zero or more addresses,
20 /* rewrites each address to canonical form, and optionally applies
21 /* an address extension to each resulting address. The caller is
22 /* expected to pass the result to argv_free().
23 /*
24 /* With mail_addr_crunch_ext_to_int(), the string is in external
25 /* form, and the result is in internal form. This API minimizes
26 /* the number of conversions between internal and external forms.
27 /*
28 /* mail_addr_crunch_opt() gives more control, at the cost of
29 /* additional conversions between internal and external forms.
30 /*
31 /* Arguments:
32 /* .IP string
33 /* A string with zero or more addresses in external (quoted)
34 /* form, or in the form specified with the in_form argument.
35 /* .IP extension
36 /* A null pointer, or an address extension (including the recipient
37 /* address delimiter) that is propagated to all result addresses.
38 /* This is in internal (unquoted) form.
39 /* .IP in_form
40 /* .IP out_form
41 /* Input and output address forms, either MA_FORM_INTERNAL
42 /* (unquoted form) or MA_FORM_EXTERNAL (quoted form).
43 /* DIAGNOSTICS
44 /* Fatal error: out of memory.
45 /* SEE ALSO
46 /* tok822_parse(3), address parser
47 /* canon_addr(3), address canonicalization
48 /* LICENSE
49 /* .ad
50 /* .fi
51 /* The Secure Mailer license must be distributed with this software.
52 /* AUTHOR(S)
53 /* Wietse Venema
54 /* IBM T.J. Watson Research
55 /* P.O. Box 704
56 /* Yorktown Heights, NY 10598, USA
57 /*
58 /* Wietse Venema
59 /* Google, Inc.
60 /* 111 8th Avenue
61 /* New York, NY 10011, USA
62 /*--*/
63 
64 /* System library. */
65 
66 #include <sys_defs.h>
67 #include <string.h>
68 
69 /* Utility library. */
70 
71 #include <mymalloc.h>
72 #include <argv.h>
73 #include <vstring.h>
74 
75 /* Global library. */
76 
77 #include <tok822.h>
78 #include <canon_addr.h>
79 #include <quote_822_local.h>
80 #include <mail_addr_crunch.h>
81 
82 /* mail_addr_crunch - break string into addresses, optionally add extension */
83 
84 ARGV *mail_addr_crunch_opt(const char *string, const char *extension,
85  int in_form, int out_form)
86 {
87  VSTRING *intern_addr = vstring_alloc(100);
88  VSTRING *extern_addr = vstring_alloc(100);
89  VSTRING *canon_addr = vstring_alloc(100);
90  ARGV *argv = argv_alloc(1);
91  TOK822 *tree;
92  TOK822 **addr_list;
93  TOK822 **tpp;
94  char *ratsign;
95  ssize_t extlen;
96 
97  if (extension)
98  extlen = strlen(extension);
99 
100 #define STR(x) vstring_str(x)
101 
102  /*
103  * Optionally convert input from internal form.
104  */
105  if (in_form == MA_FORM_INTERNAL) {
106  quote_822_local(extern_addr, string);
107  string = STR(extern_addr);
108  }
109 
110  /*
111  * Parse the string, rewrite each address to canonical form, and convert
112  * the result to external (quoted) form. Optionally apply the extension
113  * to each address found.
114  *
115  * XXX Workaround for the null address. This works for envelopes but
116  * produces ugly results for message headers.
117  */
118  if (*string == 0 || strcmp(string, "<>") == 0)
119  string = "\"\"";
120  tree = tok822_parse(string);
121  /* string->extern_addr would be invalidated by tok822_externalize() */
122  string = 0;
123  addr_list = tok822_grep(tree, TOK822_ADDR);
124  for (tpp = addr_list; *tpp; tpp++) {
125  tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL);
126  canon_addr_external(canon_addr, STR(extern_addr));
127  unquote_822_local(intern_addr, STR(canon_addr));
128  if (extension) {
129  VSTRING_SPACE(intern_addr, extlen + 1);
130  if ((ratsign = strrchr(STR(intern_addr), '@')) == 0) {
131  vstring_strcat(intern_addr, extension);
132  } else {
133  memmove(ratsign + extlen, ratsign, strlen(ratsign) + 1);
134  memcpy(ratsign, extension, extlen);
135  VSTRING_SKIP(intern_addr);
136  }
137  }
138  /* Optionally convert output to external form. */
139  if (out_form == MA_FORM_EXTERNAL) {
140  quote_822_local(extern_addr, STR(intern_addr));
141  argv_add(argv, STR(extern_addr), ARGV_END);
142  } else {
143  argv_add(argv, STR(intern_addr), ARGV_END);
144  }
145  }
146  argv_terminate(argv);
147  myfree((void *) addr_list);
148  tok822_free_tree(tree);
149  vstring_free(canon_addr);
150  vstring_free(extern_addr);
151  vstring_free(intern_addr);
152  return (argv);
153 }
154 
155 #ifdef TEST
156 
157  /*
158  * Stand-alone test program, sort of interactive.
159  */
160 #include <stdlib.h>
161 #include <unistd.h>
162 #include <msg.h>
163 #include <vstream.h>
164 #include <vstring_vstream.h>
165 #include <mail_conf.h>
166 #include <mail_params.h>
167 
168 /* canon_addr_external - surrogate to avoid trivial-rewrite dependency */
169 
170 VSTRING *canon_addr_external(VSTRING *result, const char *addr)
171 {
172  return (vstring_strcpy(result, addr));
173 }
174 
175 static int get_addr_form(const char *prompt, VSTRING *buf)
176 {
177  int addr_form;
178 
179  if (prompt) {
180  vstream_printf("%s: ", prompt);
182  }
184  exit(0);
185  if ((addr_form = mail_addr_form_from_string(STR(buf))) < 0)
186  msg_fatal("bad address form: %s", STR(buf));
187  return (addr_form);
188 }
189 
190 int main(int unused_argc, char **unused_argv)
191 {
192  VSTRING *extension = vstring_alloc(1);
193  VSTRING *buf = vstring_alloc(1);
194  ARGV *argv;
195  char **cpp;
196  int do_prompt = isatty(0);
197  int in_form;
198  int out_form;
199 
200  mail_conf_read();
201  if (chdir(var_queue_dir) < 0)
202  msg_fatal("chdir %s: %m", var_queue_dir);
203 
204  in_form = get_addr_form(do_prompt ? "input form" : 0, buf);
205  out_form = get_addr_form(do_prompt ? "output form" : 0, buf);
206  if (do_prompt) {
207  vstream_printf("extension: (CR for none): ");
209  }
210  if (vstring_get_nonl(extension, VSTREAM_IN) == VSTREAM_EOF)
211  exit(0);
212 
213  if (do_prompt) {
214  vstream_printf("print strings to be translated, one per line\n");
216  }
217  while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
218  argv = mail_addr_crunch_opt(STR(buf), (VSTRING_LEN(extension) ?
219  STR(extension) : 0),
220  in_form, out_form);
221  for (cpp = argv->argv; *cpp; cpp++)
222  vstream_printf("|%s|\n", *cpp);
224  argv_free(argv);
225  }
226  vstring_free(extension);
227  vstring_free(buf);
228  return (0);
229 }
230 
231 #endif
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
#define MA_FORM_INTERNAL
#define ARGV_END
Definition: argv.h:52
#define TOK822_ADDR
Definition: tok822.h:46
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
TOK822 ** tok822_grep(TOK822 *, int)
Definition: tok822_tree.c:292
Definition: argv.h:17
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
Definition: tok822.h:27
#define tok822_parse(cp)
Definition: tok822.h:84
char ** argv
Definition: argv.h:20
VSTRING * unquote_822_local(VSTRING *dst, const char *mbox)
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
#define VSTREAM_IN
Definition: vstream.h:66
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
#define VSTRING_LEN(vp)
Definition: vstring.h:72
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
TOK822 * tok822_free_tree(TOK822 *)
Definition: tok822_tree.c:262
void mail_conf_read(void)
Definition: mail_conf.c:178
#define VSTRING_SKIP(vp)
Definition: vstring.h:82
VSTRING * canon_addr_external(VSTRING *result, const char *addr)
Definition: canon_addr.c:57
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
VSTRING * tok822_externalize(VSTRING *, TOK822 *, int)
Definition: tok822_parse.c:270
#define STR(x)
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
ARGV * mail_addr_crunch_opt(const char *string, const char *extension, int in_form, int out_form)
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define TOK822_STR_DEFL
Definition: tok822.h:91
#define VSTRING_SPACE(vp, len)
Definition: vstring.h:70
#define quote_822_local(dst, src)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * var_queue_dir
Definition: mail_params.c:246
int mail_addr_form_from_string(const char *addr_form_name)
#define MA_FORM_EXTERNAL
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
void argv_terminate(ARGV *argvp)
Definition: argv.c:242