1/*
2 * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 */
9
10#pragma ident	"%Z%%M%	%I%	%E% SMI"
11
12#include <sm/gen.h>
13SM_IDSTR(id, "@(#)$Id: t-qic.c,v 1.9 2006/08/24 21:26:13 ca Exp $")
14
15#include <stdio.h>
16#include <sm/sendmail.h>
17#include <sm/assert.h>
18#include <sm/heap.h>
19#include <sm/string.h>
20#include <sm/test.h>
21
22extern bool SmTestVerbose;
23
24
25void
26show_diff(s1, s2)
27	const char *s1;
28	const char *s2;
29{
30	int i;
31
32	for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++)
33	{
34		if (s1[i] != s2[i])
35		{
36			fprintf(stderr, "i=%d, s1[]=%u, s2[]=%u\n",
37				i, (unsigned char) s1[i],
38				(unsigned char) s2[i]);
39			return;
40		}
41	}
42	if (s1[i] != s2[i])
43	{
44		fprintf(stderr, "i=%d, s1[]=%u, s2[]=%u\n",
45			i, (unsigned char) s1[i], (unsigned char) s2[i]);
46	}
47}
48
49char *quote_unquote __P((char *, char *, int, int));
50
51char *
52quote_unquote(in, out, outlen, exp)
53	char *in;
54	char *out;
55	int outlen;
56	int exp;
57{
58	char *obp, *bp;
59	char line_back[1024];
60	char line_in[1024];
61	int cmp;
62
63	sm_strlcpy(line_in, in, sizeof(line_in));
64	obp = quote_internal_chars(in, out, &outlen);
65	bp = str2prt(line_in);
66	dequote_internal_chars(obp, line_back, sizeof(line_back));
67	cmp = strcmp(line_in, line_back);
68	SM_TEST(exp == cmp);
69	if (cmp != exp && !SmTestVerbose)
70	{
71		fprintf(stderr, "in: %s\n", bp);
72		bp = str2prt(line_back);
73		fprintf(stderr, "out:%s\n", bp);
74		fprintf(stderr, "cmp=%d\n", cmp);
75		show_diff(in, line_back);
76	}
77	if (SmTestVerbose)
78	{
79		fprintf(stderr, "%s -> ", bp);
80		bp = str2prt(obp);
81		fprintf(stderr, "%s\n", bp);
82		fprintf(stderr, "cmp=%d\n", cmp);
83	}
84	return obp;
85}
86
87struct sm_qic_S
88{
89	char		*qic_in;
90	char		*qic_out;
91	int		 qic_exp;
92};
93
94typedef struct sm_qic_S sm_qic_T;
95
96
97int
98main(argc, argv)
99	int argc;
100	char *argv[];
101{
102	char line_in[1024], line[256], line_out[32], *obp;
103	int i, los, cmp;
104	sm_qic_T inout[] = {
105		  { "", "",	0 }
106		, { "abcdef", "abcdef",	0 }
107		, { "01234567890123456789", "01234567890123456789",	0 }
108		, { "01234567890123456789\001", "01234567890123456789\001",
109			0 }
110		, { "012345\2067890123456789", "012345\377\2067890123456789",
111			0 }
112		, { "\377", "\377\377",	0 }
113		, { "\240", "\240",	0 }
114		, { "\220", "\377\220",	0 }
115		, { "\240\220", "\240\377\220",	0 }
116		, { "\377\377", "\377\377\377\377",	0 }
117		, { "\377a\377b", "\377\377a\377\377b",	0 }
118		, { "\376a\377b", "\376a\377\377b",	0 }
119		, { "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240",
120		    "\377\200\377\201\377\202\377\203\377\204\377\205\377\206\377\207\377\210\377\211\377\212\377\213\377\214\377\215\377\216\377\217\377\220\377\221\377\222\377\223\377\224\377\225\377\226\377\227\377\230\377\231\377\232\377\233\377\234\377\235\377\236\377\237\240",
121			0 }
122		, { NULL, NULL,	0 }
123	};
124
125	sm_test_begin(argc, argv, "test meta quoting");
126	for (i = 0; i < sizeof(line_out); i++)
127		line_out[i] = '\0';
128	for (i = 0; i < sizeof(line_in); i++)
129		line_in[i] = '\0';
130	for (i = 0; i < sizeof(line_in) / 2; i++)
131	{
132		char ch;
133
134		ch = 0200 + i;
135		if ('\0' == ch)
136			ch = '0';
137		line_in[i] = ch;
138	}
139	los = sizeof(line_out) / 2;
140	obp = quote_unquote(line_in, line_out, los, 0);
141	if (obp != line_out)
142		SM_FREE(obp);
143
144	for (i = 0; i < sizeof(line_in); i++)
145		line_in[i] = '\0';
146	for (i = 0; i < sizeof(line_in) / 2; i++)
147	{
148		char ch;
149
150		ch = 0200 + i;
151		if ('\0' == ch)
152			ch = '0';
153		line_in[i] = ch;
154	}
155	los = sizeof(line_in);
156	obp = quote_unquote(line_in, line_in, los, 0);
157	if (obp != line_in)
158		SM_FREE(obp);
159
160	for (i = 0; inout[i].qic_in != NULL; i++)
161	{
162		los = sizeof(line_out) / 2;
163		obp = quote_unquote(inout[i].qic_in, line_out, los,
164				inout[i].qic_exp);
165		cmp = strcmp(inout[i].qic_out, obp);
166		SM_TEST(inout[i].qic_exp == cmp);
167		if (inout[i].qic_exp != cmp && !SmTestVerbose)
168		{
169			char *bp;
170
171			bp = str2prt(obp);
172			fprintf(stderr, "got: %s\n", bp);
173			bp = str2prt(inout[i].qic_out);
174			fprintf(stderr, "exp:%s\n", bp);
175			fprintf(stderr, "cmp=%d\n", cmp);
176			show_diff(inout[i].qic_in, inout[i].qic_out);
177		}
178		if (obp != line_out)
179			SM_FREE(obp);
180	}
181
182	/* use same buffer for in and out */
183	for (i = 0; inout[i].qic_in != NULL; i++)
184	{
185		bool same;
186
187		same = strcmp(inout[i].qic_in, inout[i].qic_out) == 0;
188		los = sm_strlcpy(line, inout[i].qic_in, sizeof(line));
189		SM_TEST(los + 1 < sizeof(line));
190		++los;
191		obp = quote_unquote(line, line, los, inout[i].qic_exp);
192		cmp = strcmp(inout[i].qic_out, obp);
193		SM_TEST(inout[i].qic_exp == cmp);
194		if (inout[i].qic_exp != cmp && !SmTestVerbose)
195		{
196			char *bp;
197
198			bp = str2prt(obp);
199			fprintf(stderr, "got: %s\n", bp);
200			bp = str2prt(inout[i].qic_out);
201			fprintf(stderr, "exp:%s\n", bp);
202			fprintf(stderr, "cmp=%d\n", cmp);
203			show_diff(inout[i].qic_in, inout[i].qic_out);
204		}
205		if (obp != line)
206		{
207			SM_TEST(!same);
208			if (same)
209				show_diff(obp, inout[i].qic_out);
210			SM_FREE(obp);
211		}
212	}
213
214	/* use NULL buffer for out */
215	for (i = 0; inout[i].qic_in != NULL; i++)
216	{
217		los = 0;
218		obp = quote_unquote(inout[i].qic_in, NULL, los,
219				inout[i].qic_exp);
220		SM_TEST(obp != NULL);
221		cmp = strcmp(inout[i].qic_out, obp);
222		SM_TEST(inout[i].qic_exp == cmp);
223		if (inout[i].qic_exp != cmp && !SmTestVerbose)
224		{
225			char *bp;
226
227			bp = str2prt(obp);
228			fprintf(stderr, "got: %s\n", bp);
229			bp = str2prt(inout[i].qic_out);
230			fprintf(stderr, "exp:%s\n", bp);
231			fprintf(stderr, "cmp=%d\n", cmp);
232			show_diff(inout[i].qic_in, inout[i].qic_out);
233		}
234	}
235
236	return sm_test_end();
237}
238