xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/mail_addr_crunch.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: mail_addr_crunch.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	mail_addr_crunch 3
6 /* SUMMARY
7 /*	parse and canonicalize addresses, apply address extension
8 /* SYNOPSIS
9 /*	#include <mail_addr_crunch.h>
10 /*
11 /*	ARGV	*mail_addr_crunch(string, extension)
12 /*	const char *string;
13 /*	const char *extension;
14 /* DESCRIPTION
15 /*	mail_addr_crunch() parses a string with zero or more addresses,
16 /*	rewrites each address to canonical form, and optionally applies
17 /*	an address extension to each resulting address. Input and result
18 /*	are in external (quoted) format. The caller is expected to pass
19 /*	the result to argv_free().
20 /*
21 /*	Arguments:
22 /* .IP string
23 /*	A string with zero or more addresses in RFC 822 (external) format.
24 /* .IP extension
25 /*	A null pointer, or an address extension (including the recipient
26 /*	address delimiter) that is propagated to all result addresses.
27 /* DIAGNOSTICS
28 /*	Fatal error: out of memory.
29 /* SEE ALSO
30 /*	tok822_parse(3), address parser
31 /*	canon_addr(3), address canonicalization
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /*	The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /*	Wietse Venema
38 /*	IBM T.J. Watson Research
39 /*	P.O. Box 704
40 /*	Yorktown Heights, NY 10598, USA
41 /*--*/
42 
43 /* System library. */
44 
45 #include <sys_defs.h>
46 #include <string.h>
47 
48 /* Utility library. */
49 
50 #include <mymalloc.h>
51 #include <argv.h>
52 #include <vstring.h>
53 
54 /* Global library. */
55 
56 #include <tok822.h>
57 #include <canon_addr.h>
58 #include <mail_addr_crunch.h>
59 
60 /* mail_addr_crunch - break string into addresses, optionally add extension */
61 
62 ARGV   *mail_addr_crunch(const char *string, const char *extension)
63 {
64     VSTRING *extern_addr = vstring_alloc(100);
65     VSTRING *canon_addr = vstring_alloc(100);
66     ARGV   *argv = argv_alloc(1);
67     TOK822 *tree;
68     TOK822 **addr_list;
69     TOK822 **tpp;
70     char   *ratsign;
71     ssize_t extlen;
72 
73     if (extension)
74 	extlen = strlen(extension);
75 
76 #define STR(x) vstring_str(x)
77 
78     /*
79      * Parse the string, rewrite each address to canonical form, and convert
80      * the result to external (quoted) form. Optionally apply the extension
81      * to each address found.
82      *
83      * XXX Workaround for the null address. This works for envelopes but
84      * produces ugly results for message headers.
85      */
86     if (*string == 0 || strcmp(string, "<>") == 0)
87 	string = "\"\"";
88     tree = tok822_parse(string);
89     addr_list = tok822_grep(tree, TOK822_ADDR);
90     for (tpp = addr_list; *tpp; tpp++) {
91 	tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL);
92 	canon_addr_external(canon_addr, STR(extern_addr));
93 	if (extension) {
94 	    VSTRING_SPACE(canon_addr, extlen + 1);
95 	    if ((ratsign = strrchr(STR(canon_addr), '@')) == 0) {
96 		vstring_strcat(canon_addr, extension);
97 	    } else {
98 		memmove(ratsign + extlen, ratsign, strlen(ratsign) + 1);
99 		memcpy(ratsign, extension, extlen);
100 		VSTRING_SKIP(canon_addr);
101 	    }
102 	}
103 	argv_add(argv, STR(canon_addr), ARGV_END);
104     }
105     argv_terminate(argv);
106     myfree((void *) addr_list);
107     tok822_free_tree(tree);
108     vstring_free(canon_addr);
109     vstring_free(extern_addr);
110     return (argv);
111 }
112 
113 #ifdef TEST
114 
115  /*
116   * Stand-alone test program, sort of interactive.
117   */
118 #include <stdlib.h>
119 #include <unistd.h>
120 #include <msg.h>
121 #include <vstream.h>
122 #include <vstring_vstream.h>
123 #include <mail_conf.h>
124 #include <mail_params.h>
125 
126 int     main(int unused_argc, char **unused_argv)
127 {
128     VSTRING *extension = vstring_alloc(1);
129     VSTRING *buf = vstring_alloc(1);
130     ARGV   *argv;
131     char  **cpp;
132 
133     mail_conf_read();
134     if (chdir(var_queue_dir) < 0)
135 	msg_fatal("chdir %s: %m", var_queue_dir);
136 
137     vstream_printf("extension: (CR for none): ");
138     vstream_fflush(VSTREAM_OUT);
139     if (vstring_get_nonl(extension, VSTREAM_IN) == VSTREAM_EOF)
140 	exit(0);
141 
142     vstream_printf("print strings to be translated, one per line\n");
143     vstream_fflush(VSTREAM_OUT);
144     while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
145 	argv = mail_addr_crunch(STR(buf), VSTRING_LEN(extension) ? STR(extension) : 0);
146 	for (cpp = argv->argv; *cpp; cpp++)
147 	    vstream_printf("	%s\n", *cpp);
148 	vstream_fflush(VSTREAM_OUT);
149     }
150     return (0);
151 }
152 
153 #endif
154