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