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