1/*	$NetBSD: strip_addr.c,v 1.4 2022/10/08 16:12:45 christos Exp $	*/
2
3/*++
4/* NAME
5/*	strip_addr 3
6/* SUMMARY
7/*	strip extension from full or localpart-only address
8/* SYNOPSIS
9/*	#include <strip_addr.h>
10/*
11/*	char	*strip_addr_internal(address, extension, delimiter_set)
12/*	const char *address;
13/*	char	**extension;
14/*	const char *delimiter_set;
15/* LEGACY SUPPORT
16/*	char	*strip_addr(address, extension, delimiter_set)
17/*	const char *address;
18/*	char	**extension;
19/*	const char *delimiter_set;
20/* DESCRIPTION
21/*	strip_addr*() takes an address and either returns a null
22/*	pointer when the address contains no address extension,
23/*	or returns a copy of the address without address extension.
24/*	The caller is expected to pass the copy to myfree().
25/*
26/*	With strip_addr_internal(), the input and result are in
27/*	internal form.
28/*
29/*	strip_addr() is a backwards-compatible form for legacy code.
30/*
31/*	Arguments:
32/* .IP address
33/*	Address localpart or user@domain form.
34/* .IP extension
35/*	A null pointer, or the address of a pointer that is set to
36/*	the address of a dynamic memory copy of the address extension
37/*	that had to be chopped off.
38/*	The copy includes the recipient address delimiter.
39/*	The caller is expected to pass the copy to myfree().
40/* .IP delimiter_set
41/*	Set of recipient address delimiter characters.
42/* SEE ALSO
43/*	split_addr(3) strip extension from localpart
44/* LICENSE
45/* .ad
46/* .fi
47/*	The Secure Mailer license must be distributed with this software.
48/* AUTHOR(S)
49/*	Wietse Venema
50/*	IBM T.J. Watson Research
51/*	P.O. Box 704
52/*	Yorktown Heights, NY 10598, USA
53/*
54/*	Wietse Venema
55/*	Google, Inc.
56/*	111 8th Avenue
57/*	New York, NY 10011, USA
58/*--*/
59
60/* System library. */
61
62#include <sys_defs.h>
63#include <string.h>
64
65/* Utility library. */
66
67#include <mymalloc.h>
68
69/* Global library. */
70
71#include <split_addr.h>
72#include <strip_addr.h>
73
74/* strip_addr - strip extension from address */
75
76char   *strip_addr_internal(const char *full, char **extension,
77			            const char *delimiter_set)
78{
79    char   *ratsign;
80    char   *extent;
81    char   *saved_ext;
82    char   *stripped;
83
84    /*
85     * A quick test to eliminate inputs without delimiter anywhere.
86     */
87    if (*delimiter_set == 0 || full[strcspn(full, delimiter_set)] == 0) {
88	stripped = saved_ext = 0;
89    } else {
90	stripped = mystrdup(full);
91	if ((ratsign = strrchr(stripped, '@')) != 0)
92	    *ratsign = 0;
93	if ((extent = split_addr(stripped, delimiter_set)) != 0) {
94	    extent -= 1;
95	    if (extension) {
96		*extent = full[strlen(stripped)];
97		saved_ext = mystrdup(extent);
98		*extent = 0;
99	    } else
100		saved_ext = 0;
101	    if (ratsign != 0) {
102		*ratsign = '@';
103		memmove(extent, ratsign, strlen(ratsign) + 1);
104	    }
105	} else {
106	    myfree(stripped);
107	    stripped = saved_ext = 0;
108	}
109    }
110    if (extension)
111	*extension = saved_ext;
112    return (stripped);
113}
114
115#ifdef TEST
116
117#include <msg.h>
118#include <mail_params.h>
119
120int     main(int unused_argc, char **unused_argv)
121{
122    char   *extension;
123    char   *stripped;
124    char   *delim = "+-";
125
126#define NO_DELIM	""
127
128    /*
129     * No static initializer, because this is owned by a library.
130     */
131    var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
132
133    /*
134     * Incredible. This function takes only three arguments, and the tests
135     * already take more lines of code than the code being tested.
136     */
137    stripped = strip_addr_internal("foo", (char **) 0, NO_DELIM);
138    if (stripped != 0)
139	msg_panic("strip_addr botch 1");
140
141    stripped = strip_addr_internal("foo", &extension, NO_DELIM);
142    if (stripped != 0)
143	msg_panic("strip_addr botch 2");
144    if (extension != 0)
145	msg_panic("strip_addr botch 3");
146
147    stripped = strip_addr_internal("foo", (char **) 0, delim);
148    if (stripped != 0)
149	msg_panic("strip_addr botch 4");
150
151    stripped = strip_addr_internal("foo", &extension, delim);
152    if (stripped != 0)
153	msg_panic("strip_addr botch 5");
154    if (extension != 0)
155	msg_panic("strip_addr botch 6");
156
157    stripped = strip_addr_internal("foo@bar", (char **) 0, NO_DELIM);
158    if (stripped != 0)
159	msg_panic("strip_addr botch 7");
160
161    stripped = strip_addr_internal("foo@bar", &extension, NO_DELIM);
162    if (stripped != 0)
163	msg_panic("strip_addr botch 8");
164    if (extension != 0)
165	msg_panic("strip_addr botch 9");
166
167    stripped = strip_addr_internal("foo@bar", (char **) 0, delim);
168    if (stripped != 0)
169	msg_panic("strip_addr botch 10");
170
171    stripped = strip_addr_internal("foo@bar", &extension, delim);
172    if (stripped != 0)
173	msg_panic("strip_addr botch 11");
174    if (extension != 0)
175	msg_panic("strip_addr botch 12");
176
177    stripped = strip_addr_internal("foo-ext", (char **) 0, NO_DELIM);
178    if (stripped != 0)
179	msg_panic("strip_addr botch 13");
180
181    stripped = strip_addr_internal("foo-ext", &extension, NO_DELIM);
182    if (stripped != 0)
183	msg_panic("strip_addr botch 14");
184    if (extension != 0)
185	msg_panic("strip_addr botch 15");
186
187    stripped = strip_addr_internal("foo-ext", (char **) 0, delim);
188    if (stripped == 0)
189	msg_panic("strip_addr botch 16");
190    msg_info("wanted:    foo-ext -> %s", "foo");
191    msg_info("strip_addr foo-ext -> %s", stripped);
192    myfree(stripped);
193
194    stripped = strip_addr_internal("foo-ext", &extension, delim);
195    if (stripped == 0)
196	msg_panic("strip_addr botch 17");
197    if (extension == 0)
198	msg_panic("strip_addr botch 18");
199    msg_info("wanted:    foo-ext -> %s %s", "foo", "-ext");
200    msg_info("strip_addr foo-ext -> %s %s", stripped, extension);
201    myfree(stripped);
202    myfree(extension);
203
204    stripped = strip_addr_internal("foo-ext@bar", (char **) 0, NO_DELIM);
205    if (stripped != 0)
206	msg_panic("strip_addr botch 19");
207
208    stripped = strip_addr_internal("foo-ext@bar", &extension, NO_DELIM);
209    if (stripped != 0)
210	msg_panic("strip_addr botch 20");
211    if (extension != 0)
212	msg_panic("strip_addr botch 21");
213
214    stripped = strip_addr_internal("foo-ext@bar", (char **) 0, delim);
215    if (stripped == 0)
216	msg_panic("strip_addr botch 22");
217    msg_info("wanted:    foo-ext@bar -> %s", "foo@bar");
218    msg_info("strip_addr foo-ext@bar -> %s", stripped);
219    myfree(stripped);
220
221    stripped = strip_addr_internal("foo-ext@bar", &extension, delim);
222    if (stripped == 0)
223	msg_panic("strip_addr botch 23");
224    if (extension == 0)
225	msg_panic("strip_addr botch 24");
226    msg_info("wanted:    foo-ext@bar -> %s %s", "foo@bar", "-ext");
227    msg_info("strip_addr foo-ext@bar -> %s %s", stripped, extension);
228    myfree(stripped);
229    myfree(extension);
230
231    stripped = strip_addr_internal("foo+ext@bar", &extension, delim);
232    if (stripped == 0)
233	msg_panic("strip_addr botch 25");
234    if (extension == 0)
235	msg_panic("strip_addr botch 26");
236    msg_info("wanted:    foo+ext@bar -> %s %s", "foo@bar", "+ext");
237    msg_info("strip_addr foo+ext@bar -> %s %s", stripped, extension);
238    myfree(stripped);
239    myfree(extension);
240
241    stripped = strip_addr_internal("foo bar+ext", &extension, delim);
242    if (stripped == 0)
243	msg_panic("strip_addr botch 27");
244    if (extension == 0)
245	msg_panic("strip_addr botch 28");
246    msg_info("wanted:    foo bar+ext -> %s %s", "foo bar", "+ext");
247    msg_info("strip_addr foo bar+ext -> %s %s", stripped, extension);
248    myfree(stripped);
249    myfree(extension);
250
251    return (0);
252}
253
254#endif
255