1/*	$NetBSD$	*/
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
62ARGV   *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((char *) 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
126int     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