1 /*	$NetBSD: aliaslist.c,v 1.4 2014/12/10 04:37:55 christos Exp $	*/
2 
3 #ifndef lint
4 static char *rcsid = "Id: aliaslist.c,v 1.1 2003/06/04 00:25:47 marka Exp ";
5 #endif
6 
7 /*
8  * Copyright (c) 2002 Japan Network Information Center.  All rights reserved.
9  *
10  * By using this file, you agree to the terms and conditions set forth bellow.
11  *
12  * 			LICENSE TERMS AND CONDITIONS
13  *
14  * The following License Terms and Conditions apply, unless a different
15  * license is obtained from Japan Network Information Center ("JPNIC"),
16  * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
17  * Chiyoda-ku, Tokyo 101-0047, Japan.
18  *
19  * 1. Use, Modification and Redistribution (including distribution of any
20  *    modified or derived work) in source and/or binary forms is permitted
21  *    under this License Terms and Conditions.
22  *
23  * 2. Redistribution of source code must retain the copyright notices as they
24  *    appear in each source code file, this License Terms and Conditions.
25  *
26  * 3. Redistribution in binary form must reproduce the Copyright Notice,
27  *    this License Terms and Conditions, in the documentation and/or other
28  *    materials provided with the distribution.  For the purposes of binary
29  *    distribution the "Copyright Notice" refers to the following language:
30  *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
31  *
32  * 4. The name of JPNIC may not be used to endorse or promote products
33  *    derived from this Software without specific prior written approval of
34  *    JPNIC.
35  *
36  * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
37  *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38  *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
39  *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
40  *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45  *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
46  *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
47  */
48 
49 #include <config.h>
50 
51 #include <stddef.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <ctype.h>
56 
57 #include <idn/aliaslist.h>
58 #include <idn/assert.h>
59 #include <idn/logmacro.h>
60 #include <idn/result.h>
61 
62 struct aliasitem {
63 	char *pattern;			/* name pattern */
64 	char *encoding;			/* MIME-preferred charset name */
65 	struct aliasitem *next;
66 };
67 typedef struct aliasitem *aliasitem_t;
68 
69 struct idn__aliaslist {
70 	aliasitem_t first_item;		/* first item of the list */
71 };
72 
73 static idn_result_t
74 additem_to_top(idn__aliaslist_t list,
75 	       const char *pattern, const char *encoding);
76 
77 static idn_result_t
78 additem_to_bottom(idn__aliaslist_t list,
79 		  const char *pattern, const char *encoding);
80 
81 static int		match(const char *pattern, const char *str);
82 
83 static idn_result_t	create_item(const char *pattern, const char *encoding,
84 				    aliasitem_t *itemp);
85 
86 #ifdef DEBUG
87 static void		dump_list(idn__aliaslist_t list);
88 #endif
89 
90 idn_result_t
91 idn__aliaslist_create(idn__aliaslist_t *listp) {
92 	static int size = sizeof(struct idn__aliaslist);
93 
94 	TRACE(("idn__aliaslist_create()\n"));
95 
96 	assert(listp != NULL);
97 
98 	if ((*listp = malloc(size)) == NULL) {
99 		return (idn_nomemory);
100 	}
101 	(*listp)->first_item = NULL;
102 
103 	return (idn_success);
104 }
105 
106 void
107 idn__aliaslist_destroy(idn__aliaslist_t list) {
108 	aliasitem_t current;
109 	aliasitem_t next;
110 
111 	TRACE(("idn__aliaslist_destroy()\n"));
112 
113 	assert(list != NULL);
114 
115 	current = list->first_item;
116 	while (current != NULL) {
117 		if (current->pattern != NULL) {
118 			free(current->pattern);
119 		}
120 		if (current->encoding != NULL) {
121 			free(current->encoding);
122 		}
123 		next = current->next;
124 		free(current);
125 		current = next;
126 	}
127 	free(list);
128 }
129 
130 idn_result_t
131 idn__aliaslist_aliasfile(idn__aliaslist_t list, const char *path) {
132 	FILE *fp;
133 	int line_no;
134 	idn_result_t r = idn_success;
135 	char line[200], alias[200], real[200];
136 
137 	assert(path != NULL);
138 
139 	TRACE(("idn__aliaslist_aliasfile(path=%s)\n", path));
140 
141 	if ((fp = fopen(path, "r")) == NULL) {
142 		return (idn_nofile);
143 	}
144 	for (line_no = 1; fgets(line, sizeof(line), fp) != NULL; line_no++) {
145 		unsigned char *p = (unsigned char *)line;
146 
147 		while (isascii(*p) && isspace(*p))
148 			p++;
149 		if (*p == '#' || *p == '\n')
150 			continue;
151 		if (sscanf((char *)p, "%s %s", alias, real) == 2) {
152 			r = additem_to_bottom(list, alias, real);
153 			if (r != idn_success)
154 				break;
155 		} else {
156 			INFO(("idn__aliaslist_aliasfile: file %s has "
157 			      "invalid contents at line %d\n",
158 			      path, line_no));
159 			r = idn_invalid_syntax;
160 			break;
161 		}
162 	}
163 	fclose(fp);
164 
165 #ifdef DEBUG
166 	dump_list(list);
167 #endif
168 
169 	return (r);
170 }
171 
172 idn_result_t
173 idn__aliaslist_additem(idn__aliaslist_t list,
174 		       const char *pattern, const char *encoding,
175 		       int first_item) {
176 	if (first_item) {
177 		return additem_to_top(list, pattern, encoding);
178 	} else {
179 		return additem_to_bottom(list, pattern, encoding);
180 	}
181 }
182 
183 static idn_result_t
184 additem_to_top(idn__aliaslist_t list,
185 	       const char *pattern, const char *encoding) {
186 	aliasitem_t new_item;
187 	idn_result_t r;
188 
189 	TRACE(("additem_to_top()\n"));
190 
191 	assert(list != NULL);
192 	assert(pattern != NULL);
193 	assert(encoding != NULL);
194 
195 	if ((r = create_item(pattern, encoding, &new_item))
196 	    != idn_success) {
197 		WARNING(("additem_to_top: malloc failed\n"));
198 		return (r);
199 	}
200 
201 	new_item->next = list->first_item;
202 	list->first_item = new_item;
203 
204 #ifdef DEBUG
205 	dump_list(list);
206 #endif
207 
208 	return (idn_success);
209 }
210 
211 static idn_result_t
212 additem_to_bottom(idn__aliaslist_t list,
213 		  const char *pattern, const char *encoding) {
214 	aliasitem_t new_item;
215 	idn_result_t r;
216 
217 	TRACE(("additem_to_bottom()\n"));
218 
219 	assert(list != NULL);
220 	assert(pattern != NULL);
221 	assert(encoding != NULL);
222 
223 	r = create_item(pattern, encoding, &new_item);
224 	if (r != idn_success) {
225 		WARNING(("additem_to_bottom: malloc failed\n"));
226 		return r;
227 	}
228 
229 	if (list->first_item == NULL) {
230 		list->first_item = new_item;
231 	} else {
232 		aliasitem_t cur_item = list->first_item;
233 		for (;;) {
234 			if (cur_item->next == NULL) {
235 				break;
236 			}
237 			cur_item = cur_item->next;
238 		}
239 		cur_item->next = new_item;
240 	}
241 
242 	return (idn_success);
243 }
244 
245 idn_result_t
246 idn__aliaslist_find(idn__aliaslist_t list,
247 		   const char *pattern, char **encodingp) {
248 	aliasitem_t current;
249 
250 	TRACE(("idn__aliaslist_find()\n"));
251 
252 	assert(list != NULL);
253 	assert(pattern != NULL);
254 
255 #ifdef DEBUG
256 	DUMP(("target pattern: %s\n", pattern));
257 #endif
258 	current = list->first_item;
259 	while (current != NULL) {
260 #ifdef DEBUG
261 		DUMP(("current pattern: %s, encoding: %s\n",
262 		      current->pattern, current->encoding));
263 #endif
264 		if (match(current->pattern, pattern)) {
265 			*encodingp = current->encoding;
266 			return (idn_success);
267 		}
268 		current = current->next;
269 	}
270 
271 	TRACE(("idn__aliaslist_find(): not found\n"));
272 	*encodingp = (char *)pattern;
273 	return (idn_notfound);
274 }
275 
276 /*
277  * Wild card matching function that supports only '*'.
278  */
279 static int
280 match(const char *pattern, const char *str) {
281 	for (;;) {
282 		int c;
283 
284 		switch (c = *pattern++) {
285 		case '\0':
286 			return (*str == '\0');
287 		case '*':
288 			while (!match(pattern, str)) {
289 				if (*str == '\0')
290 					return (0);
291 				str++;
292 			}
293 			return (1);
294 			break;
295 		default:
296 			if (*str++ != c)
297 				return (0);
298 			break;
299 		}
300 	}
301 }
302 
303 /*
304  * List item creation.
305  * pattern and encoding must not be NULL.
306  */
307 static idn_result_t
308 create_item(const char *pattern, const char *encoding,
309 	    aliasitem_t *itemp) {
310 	static size_t size = sizeof(struct aliasitem);
311 
312 	assert(pattern != NULL);
313 	assert(encoding != NULL);
314 
315 	if ((*itemp = malloc(size)) == NULL)
316 		return (idn_nomemory);
317 
318 	if (((*itemp)->pattern = malloc(strlen(pattern) + 1)) == NULL) {
319 		free(*itemp);
320 		*itemp = NULL;
321 		return (idn_nomemory);
322 	}
323 
324 	if (((*itemp)->encoding = malloc(strlen(encoding) + 1)) == NULL) {
325 		free((*itemp)->pattern);
326 		free(*itemp);
327 		*itemp = NULL;
328 		return (idn_nomemory);
329 	}
330 
331 	(void)strcpy((*itemp)->pattern, pattern);
332 	(void)strcpy((*itemp)->encoding, encoding);
333 	(*itemp)->next = NULL;
334 
335 	return (idn_success);
336 }
337 
338 #ifdef DEBUG
339 static void
340 dump_list(idn__aliaslist_t list) {
341 	aliasitem_t item;
342 	int i;
343 
344 	TRACE(("dump_list()\n"));
345 	if (list == NULL) {
346 		TRACE(("list is NULL\n"));
347 		return;
348 	}
349 	item = list->first_item;
350 	i = 0;
351 	while (item != NULL) {
352 		DUMP(("%d: %s\t%s\n", i, item->pattern, item->encoding));
353 		item = item->next;
354 		i++;
355 	}
356 }
357 #endif
358