1 /*	$NetBSD: resconf.c,v 1.4 2014/12/10 04:37:55 christos Exp $	*/
2 
3 #ifndef lint
4 static char *rcsid = "Id: resconf.c,v 1.1 2003/06/04 00:26:12 marka Exp ";
5 #endif
6 
7 /*
8  * Copyright (c) 2000 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 <stdarg.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #ifdef HAVE_PWD_H
62 #include <pwd.h>
63 #endif
64 
65 #include <idn/result.h>
66 #include <idn/assert.h>
67 #include <idn/logmacro.h>
68 #include <idn/converter.h>
69 #include <idn/nameprep.h>
70 #include <idn/normalizer.h>
71 #include <idn/checker.h>
72 #include <idn/mapper.h>
73 #include <idn/mapselector.h>
74 #include <idn/delimitermap.h>
75 #include <idn/localencoding.h>
76 #include <idn/resconf.h>
77 #include <idn/debug.h>
78 #include <idn/util.h>
79 
80 #ifdef WIN32
81 #define MAX_PATH_SIZE		500	/* a good longer than MAX_PATH */
82 #define IDNVAL_CONFFILE		"ConfFile"
83 #else /* WIN32 */
84 
85 #ifndef IDN_RESCONF_DIR
86 #define IDN_RESCONF_DIR		"/etc"
87 #endif
88 #define IDN_RESCONF_FILE	IDN_RESCONF_DIR "/idn.conf"
89 #define IDN_USER_RESCONF_FILE	"/.idnrc"
90 
91 #endif /* WIN32 */
92 
93 #define MAX_CONF_LINE_LENGTH	255
94 #define MAX_CONF_LINE_ARGS	63
95 
96 #define DEFAULT_CONF_NAMEPREP		0x0001
97 #define DEFAULT_CONF_IDN_ENCODING	0x0010
98 #define DEFAULT_CONF_ALL		(DEFAULT_CONF_NAMEPREP | \
99 					DEFAULT_CONF_IDN_ENCODING)
100 
101 #define IDN_ENCODING_CURRENT	"Punycode"
102 
103 #ifdef ENABLE_MDNKIT_COMPAT
104 #define MDN_RESCONF_FILE	IDN_RESCONF_DIR "/mdn.conf"
105 #endif
106 
107 struct idn_resconf {
108 	int local_converter_is_static;
109 	idn_converter_t local_converter;
110 	idn_converter_t idn_converter;
111         idn_converter_t aux_idn_converter;
112 	idn_normalizer_t normalizer;
113 	idn_checker_t prohibit_checker;
114 	idn_checker_t unassigned_checker;
115 	idn_checker_t bidi_checker;
116 	idn_mapper_t mapper;
117 	idn_mapselector_t local_mapper;
118 	idn_delimitermap_t delimiter_mapper;
119 	int reference_count;
120 };
121 
122 static int initialized;
123 
124 #ifndef WIN32
125 static const char *	userhomedir(void);
126 #endif
127 static idn_result_t	open_userdefaultfile(FILE **fpp);
128 static idn_result_t	open_defaultfile(FILE **fpp);
129 static idn_result_t	parse_conf(idn_resconf_t ctx, FILE *fp);
130 static idn_result_t	parse_idn_encoding(idn_resconf_t ctx, char *args,
131 					   int lineno);
132 static idn_result_t	parse_local_map(idn_resconf_t ctx, char *args,
133 					int lineno);
134 static idn_result_t	parse_nameprep(idn_resconf_t ctx, char *args,
135 				       int lineno);
136 static int		split_args(char *s, char **av, int max_ac);
137 static void		resetconf(idn_resconf_t ctx);
138 #ifndef WITHOUT_ICONV
139 static idn_result_t	update_local_converter(idn_resconf_t ctx);
140 #endif
141 static idn_result_t	setdefaults_body(idn_resconf_t ctx, int conf_mask);
142 
143 idn_result_t
144 idn_resconf_initialize(void) {
145 	idn_result_t r;
146 
147 	TRACE(("idn_resconf_initialize()\n"));
148 
149 	if (initialized) {
150 		r = idn_success;
151 		goto ret;
152 	}
153 
154 	/*
155 	 * Initialize sub modules.
156 	 */
157 	if ((r = idn_converter_initialize()) != idn_success)
158 		goto ret;
159 	if ((r = idn_normalizer_initialize()) != idn_success)
160 		goto ret;
161 	if ((r = idn_checker_initialize()) != idn_success)
162 		goto ret;
163 	if ((r = idn_mapselector_initialize()) != idn_success)
164 		goto ret;
165 	if ((r = idn_mapper_initialize()) != idn_success)
166 		goto ret;
167 
168 	r = idn_success;
169 	initialized = 1;
170 ret:
171 	TRACE(("idn_resconf_initialize(): %s\n", idn_result_tostring(r)));
172 	return (r);
173 }
174 
175 idn_result_t
176 idn_resconf_create(idn_resconf_t *ctxp) {
177 	idn_resconf_t ctx = NULL;
178 	idn_result_t r;
179 
180 	assert(ctxp != NULL);
181 
182 	TRACE(("idn_resconf_create()\n"));
183 
184 	if (!initialized) {
185 		r = idn_failure;
186 		goto ret;
187 	}
188 	if ((ctx = malloc(sizeof(*ctx))) == NULL) {
189 		r = idn_nomemory;
190 		goto ret;
191 	}
192 
193 	ctx->local_converter_is_static = 0;
194 	ctx->local_converter = NULL;
195 	ctx->idn_converter = NULL;
196 	ctx->aux_idn_converter = NULL;
197 	ctx->normalizer = NULL;
198 	ctx->prohibit_checker = NULL;
199 	ctx->unassigned_checker = NULL;
200 	ctx->bidi_checker = NULL;
201 	ctx->mapper = NULL;
202 	ctx->local_mapper = NULL;
203 	ctx->reference_count = 1;
204 
205 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
206 	if (r != idn_success)
207 		goto ret;
208 
209 	*ctxp = ctx;
210 	r = idn_success;
211 ret:
212 	TRACE(("idn_resconf_create(): %s\n", idn_result_tostring(r)));
213 	return (r);
214 }
215 
216 char *
217 idn_resconf_defaultfile() {
218 #ifdef WIN32
219 	static char default_path[MAX_PATH_SIZE];
220 
221 	if (idn__util_getregistrystring(idn__util_hkey_localmachine,
222 					IDNVAL_CONFFILE, default_path,
223 					sizeof(default_path))) {
224 		return (default_path);
225 	} else {
226 		return (NULL);
227 	}
228 #else
229 	return (IDN_RESCONF_FILE);
230 #endif
231 }
232 
233 #ifndef WIN32
234 static const char *
235 userhomedir() {
236 	uid_t uid;
237 	struct passwd *pwd;
238 
239 	uid = getuid();
240 	pwd = getpwuid(uid);
241 	if (pwd == NULL) {
242 		return (NULL);
243 	}
244 
245 	return (pwd->pw_dir);
246 }
247 #endif
248 
249 static idn_result_t
250 open_userdefaultfile(FILE **fpp) {
251 #ifdef WIN32
252 	char user_path[MAX_PATH_SIZE];
253 
254 	TRACE(("open_userdefaultfile()\n"));
255 
256 	if (idn__util_getregistrystring(idn__util_hkey_currentuser,
257 					IDNVAL_CONFFILE, user_path,
258 					sizeof(user_path)) == 0) {
259 		return (idn_nofile);
260 	}
261 	*fpp = fopen(user_path, "r");
262 	if (*fpp == NULL) {
263 		return (idn_nofile);
264 	}
265 	return (idn_success);
266 #else /* WIN32 */
267 	const char *homedir;
268 	char *file;
269 	int len;
270 
271 	TRACE(("open_userdefaultfile()\n"));
272 
273 	homedir = userhomedir();
274 	len = strlen(IDN_USER_RESCONF_FILE) + 1;
275 	if (homedir != NULL) {
276 		len += strlen(homedir);
277 	} else {
278 		return (idn_notfound);
279 	}
280 
281 	file = (char *)malloc(sizeof(char) * len);
282 	if (file == NULL) {
283 		WARNING(("open_userdefaultfile(): malloc failed\n"));
284 		return (idn_nomemory);
285 	}
286 
287 	(void)strcpy(file, homedir);
288 	strcat(file, IDN_USER_RESCONF_FILE);
289 
290 	*fpp = fopen(file, "r");
291 	free(file);
292 	if (*fpp == NULL) {
293 		return (idn_nofile);
294 	}
295 
296 	return (idn_success);
297 #endif /* WIN32 */
298 }
299 
300 static idn_result_t
301 open_defaultfile(FILE **fpp) {
302 	idn_result_t r;
303 	const char *file;
304 
305 	r = open_userdefaultfile(fpp);
306 	if (r == idn_nofile || r == idn_notfound) {
307 		TRACE(("open_defaultfile: "
308 		       "cannot open user configuration file\n"));
309 		file = idn_resconf_defaultfile();
310 		*fpp = fopen(file, "r");
311 #ifdef ENABLE_MDNKIT_COMPAT
312 		if (*fpp == NULL)
313 			*fpp = fopen(MDN_RESCONF_FILE, "r");
314 #endif
315 		if (*fpp == NULL) {
316 			TRACE(("open_defaultfile: "
317 			       "cannot open system configuration file\n"));
318 			return (idn_nofile);
319 		}
320 	} else if (r != idn_success) {
321 		return (r);
322 	}
323 
324 	return (idn_success);
325 }
326 
327 idn_result_t
328 idn_resconf_loadfile(idn_resconf_t ctx, const char *file) {
329 	FILE *fp = NULL;
330 	idn_result_t r;
331 
332 	assert(ctx != NULL);
333 
334 	TRACE(("idn_resconf_loadfile(file=%s)\n",
335 	      file == NULL ? "<null>" : file));
336 
337 	resetconf(ctx);
338 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
339 	if (r != idn_success) {
340 		goto ret;
341 	}
342 
343 	if (file == NULL) {
344 		r = open_defaultfile(&fp);
345 		if (r == idn_nofile || r == idn_notfound) {
346 			r = setdefaults_body(ctx, 0);
347 			goto ret;
348 		} else if (r != idn_success) {
349 			goto ret;
350 		}
351 	} else {
352 		fp = fopen(file, "r");
353 		if (fp == NULL) {
354 			TRACE(("idn_resconf_loadfile: cannot open %-.40s\n",
355 			       file));
356 			r = idn_nofile;
357 			goto ret;
358 		}
359 	}
360 
361 	r = parse_conf(ctx, fp);
362 	fclose(fp);
363 
364 ret:
365 	TRACE(("idn_resconf_loadfile(): %s\n", idn_result_tostring(r)));
366 	return (r);
367 }
368 
369 void
370 idn_resconf_destroy(idn_resconf_t ctx) {
371 	assert(ctx != NULL);
372 
373 	TRACE(("idn_resconf_destroy()\n"));
374 
375 	ctx->reference_count--;
376 	if (ctx->reference_count <= 0) {
377 		resetconf(ctx);
378 		free(ctx);
379 		TRACE(("idn_resconf_destroy: the object is destroyed\n"));
380 	} else {
381 		TRACE(("idn_resconf_destroy(): "
382 		       "update reference count (%d->%d)\n",
383 		       ctx->reference_count + 1, ctx->reference_count));
384 	}
385 }
386 
387 void
388 idn_resconf_incrref(idn_resconf_t ctx) {
389 	assert(ctx != NULL);
390 
391 	TRACE(("idn_resconf_incrref()\n"));
392 	TRACE(("idn_resconf_incrref: update reference count (%d->%d)\n",
393 		ctx->reference_count, ctx->reference_count + 1));
394 
395 	ctx->reference_count++;
396 }
397 
398 idn_converter_t
399 idn_resconf_getalternateconverter(idn_resconf_t ctx) {
400 	assert(ctx != NULL);
401 
402 	TRACE(("idn_resconf_getalternateconverter()\n"));
403 
404 	return (idn_resconf_getidnconverter(ctx));
405 }
406 
407 idn_delimitermap_t
408 idn_resconf_getdelimitermap(idn_resconf_t ctx) {
409 	assert(ctx != NULL);
410 
411 	TRACE(("idn_resconf_getdelimitermap()\n"));
412 
413 	if (ctx->delimiter_mapper != NULL)
414 		idn_delimitermap_incrref(ctx->delimiter_mapper);
415 	return (ctx->delimiter_mapper);
416 }
417 
418 idn_converter_t
419 idn_resconf_getidnconverter(idn_resconf_t ctx) {
420 	assert(ctx != NULL);
421 
422 	TRACE(("idn_resconf_getidnconverter()\n"));
423 
424 	if (ctx->idn_converter != NULL)
425 		idn_converter_incrref(ctx->idn_converter);
426 	return (ctx->idn_converter);
427 }
428 
429 idn_converter_t
430 idn_resconf_getauxidnconverter(idn_resconf_t ctx) {
431 	assert(ctx != NULL);
432 
433 	TRACE(("idn_resconf_getauxidnconverter()\n"));
434 
435 	if (ctx->aux_idn_converter != NULL)
436 		idn_converter_incrref(ctx->aux_idn_converter);
437 	return (ctx->aux_idn_converter);
438 }
439 
440 idn_converter_t
441 idn_resconf_getlocalconverter(idn_resconf_t ctx) {
442 	assert(ctx != NULL);
443 
444 	TRACE(("idn_resconf_getlocalconverter()\n"));
445 
446 #ifdef WITHOUT_ICONV
447 	return NULL;
448 
449 #else /* WITHOUT_ICONV */
450 	if (update_local_converter(ctx) != idn_success)
451 		return (NULL);
452 
453 	idn_converter_incrref(ctx->local_converter);
454 	return (ctx->local_converter);
455 
456 #endif /* WITHOUT_ICONV */
457 }
458 
459 idn_mapselector_t
460 idn_resconf_getlocalmapselector(idn_resconf_t ctx) {
461 	assert(ctx != NULL);
462 
463 	TRACE(("idn_resconf_getlocalmapselector()\n"));
464 
465 	if (ctx->local_mapper != NULL)
466 		idn_mapselector_incrref(ctx->local_mapper);
467 	return (ctx->local_mapper);
468 }
469 
470 idn_mapper_t
471 idn_resconf_getmapper(idn_resconf_t ctx) {
472 	assert(ctx != NULL);
473 
474 	TRACE(("idn_resconf_getmapper()\n"));
475 
476 	if (ctx->mapper != NULL)
477 		idn_mapper_incrref(ctx->mapper);
478 	return (ctx->mapper);
479 }
480 
481 idn_normalizer_t
482 idn_resconf_getnormalizer(idn_resconf_t ctx) {
483 	assert(ctx != NULL);
484 
485 	TRACE(("idn_resconf_getnormalizer()\n"));
486 
487 	if (ctx->normalizer != NULL)
488 		idn_normalizer_incrref(ctx->normalizer);
489 	return (ctx->normalizer);
490 }
491 
492 idn_checker_t
493 idn_resconf_getprohibitchecker(idn_resconf_t ctx) {
494 	assert(ctx != NULL);
495 
496 	TRACE(("idn_resconf_getprohibitchecker()\n"));
497 
498 	if (ctx->prohibit_checker != NULL)
499 		idn_checker_incrref(ctx->prohibit_checker);
500 	return (ctx->prohibit_checker);
501 }
502 
503 idn_checker_t
504 idn_resconf_getunassignedchecker(idn_resconf_t ctx) {
505 	assert(ctx != NULL);
506 
507 	TRACE(("idn_resconf_getunassignedchecker()\n"));
508 
509 	if (ctx->unassigned_checker != NULL)
510 		idn_checker_incrref(ctx->unassigned_checker);
511 	return (ctx->unassigned_checker);
512 }
513 
514 idn_checker_t
515 idn_resconf_getbidichecker(idn_resconf_t ctx) {
516 	assert(ctx != NULL);
517 
518 	TRACE(("idn_resconf_getbidichecker()\n"));
519 
520 	if (ctx->bidi_checker != NULL)
521 		idn_checker_incrref(ctx->bidi_checker);
522 	return (ctx->bidi_checker);
523 }
524 
525 void
526 idn_resconf_setalternateconverter(idn_resconf_t ctx,
527 				  idn_converter_t alternate_converter) {
528 	assert(ctx != NULL);
529 
530 	TRACE(("idn_resconf_setalternateconverter()\n"));
531 }
532 
533 void
534 idn_resconf_setdelimitermap(idn_resconf_t ctx,
535 			    idn_delimitermap_t delimiter_mapper) {
536 	assert(ctx != NULL);
537 
538 	TRACE(("idn_resconf_setdelimitermap()\n"));
539 
540 	if (ctx->delimiter_mapper != NULL)
541 		idn_delimitermap_destroy(ctx->delimiter_mapper);
542 	ctx->delimiter_mapper = delimiter_mapper;
543 	if (delimiter_mapper != NULL)
544 		idn_delimitermap_incrref(ctx->delimiter_mapper);
545 }
546 
547 void
548 idn_resconf_setidnconverter(idn_resconf_t ctx,
549 			    idn_converter_t idn_converter) {
550 	assert(ctx != NULL);
551 
552 	TRACE(("idn_resconf_setidnconverter()\n"));
553 
554 	if (ctx->idn_converter != NULL)
555 		idn_converter_destroy(ctx->idn_converter);
556 	ctx->idn_converter = idn_converter;
557 	if (idn_converter != NULL)
558 		idn_converter_incrref(ctx->idn_converter);
559 }
560 
561 void
562 idn_resconf_setauxidnconverter(idn_resconf_t ctx,
563 				idn_converter_t aux_idn_converter) {
564 	assert(ctx != NULL);
565 
566 	TRACE(("idn_resconf_setauxidnconverter()\n"));
567 
568 	if (ctx->aux_idn_converter != NULL)
569 		idn_converter_destroy(ctx->aux_idn_converter);
570 	ctx->aux_idn_converter = aux_idn_converter;
571 	if (aux_idn_converter != NULL)
572 		idn_converter_incrref(ctx->aux_idn_converter);
573 }
574 
575 void
576 idn_resconf_setlocalconverter(idn_resconf_t ctx,
577 			      idn_converter_t local_converter) {
578 #ifndef WITHOUT_ICONV
579 	assert(ctx != NULL);
580 
581 	TRACE(("idn_resconf_setlocalconverter()\n"));
582 
583 	if (ctx->local_converter != NULL) {
584 		idn_converter_destroy(ctx->local_converter);
585 		ctx->local_converter = NULL;
586 	}
587 
588 	if (local_converter == NULL)
589 		ctx->local_converter_is_static = 0;
590 	else {
591 		ctx->local_converter = local_converter;
592 		idn_converter_incrref(local_converter);
593 		ctx->local_converter_is_static = 1;
594 	}
595 #endif /* WITHOUT_ICONV */
596 }
597 
598 void
599 idn_resconf_setlocalmapselector(idn_resconf_t ctx,
600 				idn_mapselector_t local_mapper) {
601 	assert(ctx != NULL);
602 
603 	TRACE(("idn_resconf_setlocalmapselector()\n"));
604 
605 	if (ctx->local_mapper != NULL)
606 		idn_mapselector_destroy(ctx->local_mapper);
607 	ctx->local_mapper = local_mapper;
608 	if (local_mapper != NULL)
609 		idn_mapselector_incrref(ctx->local_mapper);
610 }
611 
612 void
613 idn_resconf_setmapper(idn_resconf_t ctx, idn_mapper_t mapper) {
614 	assert(ctx != NULL);
615 
616 	TRACE(("idn_resconf_setmapper()\n"));
617 
618 	if (ctx->mapper != NULL)
619 		idn_mapper_destroy(ctx->mapper);
620 	ctx->mapper = mapper;
621 	if (mapper != NULL)
622 		idn_mapper_incrref(ctx->mapper);
623 }
624 
625 void
626 idn_resconf_setnormalizer(idn_resconf_t ctx, idn_normalizer_t normalizer) {
627 	assert(ctx != NULL);
628 
629 	TRACE(("idn_resconf_setnormalizer()\n"));
630 
631 	if (ctx->normalizer != NULL)
632 		idn_normalizer_destroy(ctx->normalizer);
633 	ctx->normalizer = normalizer;
634 	if (normalizer != NULL)
635 		idn_normalizer_incrref(ctx->normalizer);
636 }
637 
638 void
639 idn_resconf_setprohibitchecker(idn_resconf_t ctx,
640 			       idn_checker_t prohibit_checker) {
641 	assert(ctx != NULL);
642 
643 	TRACE(("idn_resconf_setprohibitchecker()\n"));
644 
645 	if (ctx->prohibit_checker != NULL)
646 		idn_checker_destroy(ctx->prohibit_checker);
647 	ctx->prohibit_checker = prohibit_checker;
648 	if (prohibit_checker != NULL)
649 		idn_checker_incrref(ctx->prohibit_checker);
650 }
651 
652 void
653 idn_resconf_setunassignedchecker(idn_resconf_t ctx,
654 				 idn_checker_t unassigned_checker) {
655 	assert(ctx != NULL);
656 
657 	TRACE(("idn_resconf_setunassignedchecker()\n"));
658 
659 	if (ctx->unassigned_checker != NULL)
660 		idn_checker_destroy(ctx->unassigned_checker);
661 	ctx->unassigned_checker = unassigned_checker;
662 	if (unassigned_checker != NULL)
663 		idn_checker_incrref(ctx->unassigned_checker);
664 }
665 
666 void
667 idn_resconf_setbidichecker(idn_resconf_t ctx,
668 			   idn_checker_t bidi_checker) {
669 	assert(ctx != NULL);
670 
671 	TRACE(("idn_resconf_setbidichecker()\n"));
672 
673 	if (ctx->bidi_checker != NULL)
674 		idn_checker_destroy(ctx->bidi_checker);
675 	ctx->bidi_checker = bidi_checker;
676 	if (bidi_checker != NULL)
677 		idn_checker_incrref(ctx->bidi_checker);
678 }
679 
680 idn_result_t
681 idn_resconf_setnameprepversion(idn_resconf_t ctx, const char *version)
682 {
683 	char prohibit_scheme_name[MAX_CONF_LINE_LENGTH + 1];
684 	char unassigned_scheme_name[MAX_CONF_LINE_LENGTH + 1];
685 	char bidi_scheme_name[MAX_CONF_LINE_LENGTH + 1];
686 	idn_mapper_t mapper = NULL;
687 	idn_normalizer_t normalizer = NULL;
688 	idn_checker_t prohibit_checker = NULL;
689 	idn_checker_t unassigned_checker = NULL;
690 	idn_checker_t bidi_checker = NULL;
691 	idn_result_t r;
692 
693 	assert(ctx != NULL && version != NULL);
694 
695 	TRACE(("idn_resconf_setnameprepversion()\n"));
696 
697 	/*
698 	 * Set canonical scheme names.
699 	 */
700 	if (strlen(version) + strlen(IDN_CHECKER_PROHIBIT_PREFIX)
701 	    > MAX_CONF_LINE_LENGTH) {
702 		r = idn_invalid_name;
703 		goto failure;
704 	}
705 	sprintf(prohibit_scheme_name, "%s%s",
706 	        IDN_CHECKER_PROHIBIT_PREFIX, version);
707 
708 	if (strlen(version) + strlen(IDN_CHECKER_UNASSIGNED_PREFIX)
709 	    > MAX_CONF_LINE_LENGTH) {
710 		r = idn_invalid_name;
711 		goto failure;
712 	}
713 	sprintf(unassigned_scheme_name, "%s%s",
714 	        IDN_CHECKER_UNASSIGNED_PREFIX, version);
715 
716 	if (strlen(version) + strlen(IDN_CHECKER_BIDI_PREFIX)
717 	    > MAX_CONF_LINE_LENGTH) {
718 		r = idn_invalid_name;
719 		goto failure;
720 	}
721 	sprintf(bidi_scheme_name, "%s%s",
722 	        IDN_CHECKER_BIDI_PREFIX, version);
723 
724 	/*
725 	 * Create objects.
726 	 */
727 	r = idn_mapper_create(&mapper);
728 	if (r != idn_success)
729 		goto failure;
730 	r = idn_normalizer_create(&normalizer);
731 	if (r != idn_success)
732 		goto failure;
733 	r = idn_checker_create(&prohibit_checker);
734 	if (r != idn_success)
735 		goto failure;
736 	r = idn_checker_create(&unassigned_checker);
737 	if (r != idn_success)
738 		goto failure;
739 	r = idn_checker_create(&bidi_checker);
740 	if (r != idn_success)
741 		goto failure;
742 
743 	r = idn_mapper_add(mapper, version);
744 	if (r != idn_success)
745 		goto failure;
746 	r = idn_normalizer_add(normalizer, version);
747 	if (r != idn_success)
748 		goto failure;
749 	r = idn_checker_add(prohibit_checker, prohibit_scheme_name);
750 	if (r != idn_success)
751 		goto failure;
752 	r = idn_checker_add(unassigned_checker, unassigned_scheme_name);
753 	if (r != idn_success)
754 		goto failure;
755 	r = idn_checker_add(bidi_checker, bidi_scheme_name);
756 	if (r != idn_success)
757 		goto failure;
758 
759 	/*
760 	 * Set the objects.
761 	 */
762 	idn_resconf_setmapper(ctx, mapper);
763 	idn_resconf_setnormalizer(ctx, normalizer);
764 	idn_resconf_setprohibitchecker(ctx, prohibit_checker);
765 	idn_resconf_setunassignedchecker(ctx, unassigned_checker);
766 	idn_resconf_setbidichecker(ctx, bidi_checker);
767 
768 	/*
769 	 * Destroy the objects.
770 	 */
771 	idn_mapper_destroy(mapper);
772 	idn_normalizer_destroy(normalizer);
773 	idn_checker_destroy(prohibit_checker);
774 	idn_checker_destroy(unassigned_checker);
775 	idn_checker_destroy(bidi_checker);
776 
777 	return (idn_success);
778 
779 failure:
780 	if (mapper != NULL)
781 		idn_mapper_destroy(mapper);
782 	if (normalizer != NULL)
783 		idn_normalizer_destroy(normalizer);
784 	if (prohibit_checker != NULL)
785 		idn_checker_destroy(prohibit_checker);
786 	if (unassigned_checker != NULL)
787 		idn_checker_destroy(unassigned_checker);
788 	if (bidi_checker != NULL)
789 		idn_checker_destroy(bidi_checker);
790 
791 	return (r);
792 }
793 
794 idn_result_t
795 idn_resconf_setalternateconvertername(idn_resconf_t ctx, const char *name,
796 				      int flags) {
797 	assert(ctx != NULL && name != NULL);
798 
799 	TRACE(("idn_resconf_setalternateconvertername(name=%s, flags=%d)\n",
800 	      name, flags));
801 
802 	return (idn_success);
803 }
804 
805 idn_result_t
806 idn_resconf_setidnconvertername(idn_resconf_t ctx, const char *name,
807 				int flags) {
808 	idn_converter_t idn_converter;
809 	idn_result_t r;
810 
811 	assert(ctx != NULL && name != NULL);
812 
813 	TRACE(("idn_resconf_setidnconvertername(name=%s, flags=%d)\n",
814 	      name, flags));
815 
816 	r = idn_converter_create(name, &idn_converter, flags);
817 	if (r != idn_success)
818 		return (r);
819 
820 	if (ctx->idn_converter != NULL)
821 		idn_converter_destroy(ctx->idn_converter);
822 	ctx->idn_converter = idn_converter;
823 
824 	return (idn_success);
825 }
826 
827 idn_result_t
828 idn_resconf_setauxidnconvertername(idn_resconf_t ctx, const char *name,
829 				    int flags) {
830 	idn_converter_t aux_idn_converter;
831 	const char *old_name;
832 	idn_result_t r;
833 
834 	assert(ctx != NULL && name != NULL);
835 
836 	TRACE(("idn_resconf_setauxidnconvertername(name=%s, flags=%d)\n",
837 	      name, flags));
838 
839 	if (ctx->aux_idn_converter != NULL) {
840 	    old_name = idn_converter_localencoding(ctx->aux_idn_converter);
841 	    if (old_name != NULL && strcmp(old_name, name) == 0)
842 		return (idn_success);
843 	}
844 
845 	r = idn_converter_create(name, &aux_idn_converter, flags);
846 	if (r != idn_success)
847 		return (r);
848 
849 	if (ctx->aux_idn_converter != NULL)
850 		idn_converter_destroy(ctx->aux_idn_converter);
851 	ctx->aux_idn_converter = aux_idn_converter;
852 
853 	return (idn_success);
854 }
855 
856 idn_result_t
857 idn_resconf_setlocalconvertername(idn_resconf_t ctx, const char *name,
858 				  int flags) {
859 #ifdef WITHOUT_ICONV
860 	return idn_failure;
861 
862 #else /* WITHOUT_ICONV */
863 	idn_converter_t local_converter;
864 	idn_result_t r;
865 
866 	assert(ctx != NULL);
867 
868 	TRACE(("idn_resconf_setlocalconvertername(name=%s, flags=%d)\n",
869 	      name == NULL ? "<null>" : name, flags));
870 
871 	if (ctx->local_converter != NULL) {
872 		idn_converter_destroy(ctx->local_converter);
873 		ctx->local_converter = NULL;
874 	}
875 	ctx->local_converter_is_static = 0;
876 
877 	if (name != NULL) {
878 		r = idn_converter_create(name, &local_converter, flags);
879 		if (r != idn_success)
880 			return (r);
881 		ctx->local_converter = local_converter;
882 		ctx->local_converter_is_static = 1;
883 	}
884 
885 	return (idn_success);
886 
887 #endif /* WITHOUT_ICONV */
888 }
889 
890 idn_result_t
891 idn_resconf_addalldelimitermapucs(idn_resconf_t ctx, unsigned long *v,
892 				  int nv) {
893 	idn_result_t r;
894 
895 	TRACE(("idn_resconf_addalldelimitermapucs(nv=%d)\n", nv));
896 
897 	if (ctx->delimiter_mapper == NULL) {
898 		r = idn_delimitermap_create(&(ctx->delimiter_mapper));
899 		if (r != idn_success)
900 			return (r);
901 	}
902 
903 	r = idn_delimitermap_addall(ctx->delimiter_mapper, v, nv);
904 	return (r);
905 }
906 
907 idn_result_t
908 idn_resconf_addalllocalmapselectornames(idn_resconf_t ctx, const char *tld,
909 					const char **names, int nnames) {
910 	idn_result_t r;
911 
912 	assert(ctx != NULL && names != NULL && tld != NULL);
913 
914 	TRACE(("idn_resconf_addalllocalmapselectorname(tld=%s, nnames=%d)\n",
915 	      tld, nnames));
916 
917 	if (ctx->local_mapper == NULL) {
918 		r = idn_mapselector_create(&(ctx->local_mapper));
919 		if (r != idn_success)
920 			return (r);
921 	}
922 
923 	r = idn_mapselector_addall(ctx->local_mapper, tld, names, nnames);
924 	return (r);
925 }
926 
927 idn_result_t
928 idn_resconf_addallmappernames(idn_resconf_t ctx, const char **names,
929 			      int nnames) {
930 	idn_result_t r;
931 
932 	assert(ctx != NULL && names != NULL);
933 
934 	TRACE(("idn_resconf_addallmappername()\n"));
935 
936 	if (ctx->mapper == NULL) {
937 		r = idn_mapper_create(&(ctx->mapper));
938 		if (r != idn_success)
939 			return (r);
940 	}
941 
942 	r = idn_mapper_addall(ctx->mapper, names, nnames);
943 	return (r);
944 }
945 
946 idn_result_t
947 idn_resconf_addallnormalizernames(idn_resconf_t ctx, const char **names,
948 				  int nnames) {
949 	idn_result_t r;
950 
951 	assert(ctx != NULL && names != NULL);
952 
953 	TRACE(("idn_resconf_addallnormalizername(nnames=%d)\n", nnames));
954 
955 	if (ctx->normalizer == NULL) {
956 		r = idn_normalizer_create(&(ctx->normalizer));
957 		if (r != idn_success)
958 			return (r);
959 	}
960 
961 	r = idn_normalizer_addall(ctx->normalizer, names, nnames);
962 	return (r);
963 }
964 
965 idn_result_t
966 idn_resconf_addallprohibitcheckernames(idn_resconf_t ctx, const char **names,
967 				       int nnames) {
968 	char long_name[MAX_CONF_LINE_LENGTH + 1];
969 	idn_result_t r;
970 	int i;
971 
972 	assert(ctx != NULL && names != NULL);
973 
974 	TRACE(("idn_resconf_addallprohibitcheckername(nnames=%d)\n", nnames));
975 
976 	if (ctx->prohibit_checker == NULL) {
977 		r = idn_checker_create(&(ctx->prohibit_checker));
978 		if (r != idn_success)
979 			return (r);
980 	}
981 
982 	for (i = 0; i < nnames; i++, names++) {
983 		if (strlen(*names) + strlen(IDN_CHECKER_PROHIBIT_PREFIX)
984 			> MAX_CONF_LINE_LENGTH) {
985 			return (idn_invalid_name);
986 		}
987 		strcpy(long_name, IDN_CHECKER_PROHIBIT_PREFIX);
988 		strcat(long_name, *names);
989 
990 		r = idn_checker_add(ctx->prohibit_checker, long_name);
991 		if (r != idn_success)
992 			return (r);
993 	}
994 
995 	return (idn_success);
996 }
997 
998 idn_result_t
999 idn_resconf_addallunassignedcheckernames(idn_resconf_t ctx, const char **names,
1000 					 int nnames) {
1001 	char long_name[MAX_CONF_LINE_LENGTH + 1];
1002 	idn_result_t r;
1003 	int i;
1004 
1005 	assert(ctx != NULL && names != NULL);
1006 
1007 	TRACE(("idn_resconf_addallunassignedcheckername(nnames=%d)\n",
1008 	      nnames));
1009 
1010 	if (ctx->unassigned_checker == NULL) {
1011 		r = idn_checker_create(&(ctx->unassigned_checker));
1012 		if (r != idn_success)
1013 			return (r);
1014 	}
1015 
1016 	for (i = 0; i < nnames; i++, names++) {
1017 		if (strlen(*names) + strlen(IDN_CHECKER_UNASSIGNED_PREFIX)
1018 			> MAX_CONF_LINE_LENGTH) {
1019 			return (idn_invalid_name);
1020 		}
1021 		strcpy(long_name, IDN_CHECKER_UNASSIGNED_PREFIX);
1022 		strcat(long_name, *names);
1023 
1024 		r = idn_checker_add(ctx->unassigned_checker, long_name);
1025 		if (r != idn_success)
1026 			return (r);
1027 	}
1028 
1029 	return (idn_success);
1030 }
1031 
1032 idn_result_t
1033 idn_resconf_addallbidicheckernames(idn_resconf_t ctx, const char **names,
1034 				   int nnames) {
1035 	char long_name[MAX_CONF_LINE_LENGTH + 1];
1036 	idn_result_t r;
1037 	int i;
1038 
1039 	assert(ctx != NULL && names != NULL);
1040 
1041 	TRACE(("idn_resconf_addallbidicheckername(nnames=%d)\n", nnames));
1042 
1043 	if (ctx->bidi_checker == NULL) {
1044 		r = idn_checker_create(&(ctx->bidi_checker));
1045 		if (r != idn_success)
1046 			return (r);
1047 	}
1048 
1049 	for (i = 0; i < nnames; i++, names++) {
1050 		if (strlen(*names) + strlen(IDN_CHECKER_BIDI_PREFIX)
1051 			> MAX_CONF_LINE_LENGTH) {
1052 			return (idn_invalid_name);
1053 		}
1054 		strcpy(long_name, IDN_CHECKER_BIDI_PREFIX);
1055 		strcat(long_name, *names);
1056 
1057 		r = idn_checker_add(ctx->bidi_checker, long_name);
1058 		if (r != idn_success)
1059 			return (r);
1060 	}
1061 
1062 	return (idn_success);
1063 }
1064 
1065 static idn_result_t
1066 parse_conf(idn_resconf_t ctx, FILE *fp) {
1067 	char line[MAX_CONF_LINE_LENGTH + 1];
1068 	int lineno = 0;
1069 	char *argv[3];
1070 	int argc;
1071 	idn_result_t r;
1072 	int conf_mask = 0;
1073 
1074 	TRACE(("parse_conf()\n"));
1075 
1076 	/*
1077 	 * Parse config file.  parsing of 'idn-encoding' line is
1078 	 * postponed because 'alias-file' line must be processed
1079 	 * before them.
1080 	 */
1081 	while (fgets(line, sizeof(line), fp) != NULL) {
1082 		char *newline;
1083 
1084 		lineno++;
1085 		newline = strpbrk(line, "\r\n");
1086 		if (newline != NULL)
1087 			*newline = '\0';
1088 		else if (fgetc(fp) != EOF) {
1089 			ERROR(("libidnkit: too long line \"%-.30s\", "
1090 			       "line %d\n", line, lineno));
1091 			return (idn_invalid_syntax);
1092 		}
1093 
1094 		argc = split_args(line, argv, 2);
1095 		if (argc == -1) {
1096 			ERROR(("libidnkit: syntax error, line %d\n", lineno));
1097 			return (idn_invalid_syntax);
1098 		} else if (argc == 0 || argv[0][0] == '#') {
1099 			continue;
1100 		} else if (argc == 1) {
1101 			ERROR(("libidnkit: syntax error, line %d\n", lineno));
1102 			return (idn_invalid_syntax);
1103 		}
1104 
1105 		if (strcmp(argv[0], "idn-encoding") == 0) {
1106 			if (conf_mask & DEFAULT_CONF_IDN_ENCODING) {
1107 				ERROR(("libidnkit: \"%s\" redefined, "
1108 				       "line %d\n", argv[0], lineno));
1109 				r = idn_invalid_syntax;
1110 			} else {
1111 				conf_mask |= DEFAULT_CONF_IDN_ENCODING;
1112 				r = parse_idn_encoding(ctx, argv[1], lineno);
1113 			}
1114 		} else if (strcmp(argv[0], "local-map") == 0) {
1115 			r = parse_local_map(ctx, argv[1], lineno);
1116 
1117 		} else if (strcmp(argv[0], "nameprep") == 0) {
1118 			if (conf_mask & DEFAULT_CONF_NAMEPREP) {
1119 				ERROR(("libidnkit: \"%s\" redefined, "
1120 				       "line %d\n", argv[0], lineno));
1121 				r = idn_invalid_syntax;
1122 			} else {
1123 				conf_mask |= DEFAULT_CONF_NAMEPREP;
1124 				r = parse_nameprep(ctx, argv[1], lineno);
1125 			}
1126 		} else if (strcmp(argv[0], "nameprep-map") == 0 ||
1127 			   strcmp(argv[0], "nameprep-normalize") == 0 ||
1128 			   strcmp(argv[0], "nameprep-prohibit") == 0 ||
1129 			   strcmp(argv[0], "nameprep-unassigned") == 0 ||
1130 			   strcmp(argv[0], "alias-file") == 0 ||
1131 			   strcmp(argv[0], "encoding-alias-file") == 0 ||
1132 			   strcmp(argv[0], "normalize") == 0 ||
1133 			   strcmp(argv[0], "server-encoding") == 0 ||
1134 		           strcmp(argv[0], "alternate-encoding") == 0 ||
1135 			   strcmp(argv[0], "delimiter-map") == 0) {
1136 			WARNING(("libidnkit: obsolete command \"%s\", line %d "
1137 			         "(ignored)\n", argv[0], lineno));
1138 			r = idn_success;
1139 		} else {
1140 			ERROR(("libidnkit: unknown command \"%-.30s\", "
1141 			       "line %d\n", argv[0], lineno));
1142 			r = idn_invalid_syntax;
1143 		}
1144 		if (r != idn_success)
1145 			return (r);
1146 	}
1147 
1148 	lineno++;
1149 
1150 	if (conf_mask != DEFAULT_CONF_ALL) {
1151 		return setdefaults_body(ctx, conf_mask);
1152 	}
1153 
1154 	return (idn_success);
1155 }
1156 
1157 static idn_result_t
1158 parse_idn_encoding(idn_resconf_t ctx, char *args, int lineno) {
1159 	idn_result_t r;
1160 	char *argv[MAX_CONF_LINE_ARGS + 1];
1161 	int argc;
1162 
1163 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1164 
1165 	if (argc != 1) {
1166 		ERROR(("libidnkit: wrong # of args for idn-encoding, "
1167 		       "line %d\n", lineno));
1168 		return (idn_invalid_syntax);
1169 	}
1170 
1171 	r = idn_converter_create(argv[0], &ctx->idn_converter,
1172 				 IDN_CONVERTER_DELAYEDOPEN |
1173 				 IDN_CONVERTER_RTCHECK);
1174 	if (r != idn_success) {
1175 		ERROR(("libidnkit: cannot create idn converter, %s, "
1176 		       "line %d\n", idn_result_tostring(r), lineno));
1177 	}
1178 
1179 	return (r);
1180 }
1181 
1182 static idn_result_t
1183 parse_local_map(idn_resconf_t ctx, char *args, int lineno) {
1184 	idn_result_t r;
1185 	char *argv[MAX_CONF_LINE_ARGS + 1];
1186 	int argc;
1187 	int i;
1188 
1189 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1190 
1191 	if (argc < 2 || argc > MAX_CONF_LINE_ARGS) {
1192 		ERROR(("libidnkit: wrong # of args for local-map, line %d\n",
1193 		       lineno));
1194 		return (idn_invalid_syntax);
1195 	}
1196 
1197 	if (ctx->local_mapper == NULL) {
1198 		r = idn_mapselector_create(&ctx->local_mapper);
1199 		if (r != idn_success) {
1200 			ERROR(("libidnkit: cannot create local mapper, %s, "
1201 			       "line %d\n", idn_result_tostring(r), lineno));
1202 			return (r);
1203 		}
1204 	}
1205 
1206 	for (i = 1; i < argc; i++) {
1207 		r = idn_mapselector_add(ctx->local_mapper, argv[0], argv[i]);
1208 		if (r == idn_invalid_name) {
1209 			ERROR(("libidnkit: map scheme unavailable \"%-.30s\""
1210 			       " or invalid TLD \"%-.30s\", line %d\n",
1211 			       argv[i], argv[0], lineno));
1212 			return (r);
1213 		} else if (r != idn_success) {
1214 			return (r);
1215 		}
1216 	}
1217 
1218 	return (idn_success);
1219 }
1220 
1221 static idn_result_t
1222 parse_nameprep(idn_resconf_t ctx, char *args, int lineno) {
1223 	idn_result_t r;
1224 	char *argv[MAX_CONF_LINE_ARGS + 1];
1225 	char scheme_name[MAX_CONF_LINE_LENGTH + 1];
1226 	int argc;
1227 
1228 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1229 
1230 	if (argc != 1) {
1231 		ERROR(("libidnkit: wrong # of args for nameprep, line %d\n",
1232 		       lineno));
1233 		return (idn_invalid_syntax);
1234 	}
1235 
1236 	/*
1237 	 * Set mapper.
1238 	 */
1239 	r = idn_mapper_create(&ctx->mapper);
1240 	if (r != idn_success) {
1241 		ERROR(("libidnkit: cannot create mapper, %s, line %d\n",
1242 		       idn_result_tostring(r), lineno));
1243 		return (r);
1244 	}
1245 
1246 	r = idn_mapper_add(ctx->mapper, argv[0]);
1247 	if (r == idn_invalid_name) {
1248 		ERROR(("libidnkit: map scheme unavailable \"%-.30s\", "
1249 		       "line %d\n", argv[0], lineno));
1250 		return (r);
1251 	} else if (r != idn_success) {
1252 		return (r);
1253 	}
1254 
1255 	/*
1256 	 * Set normalizer.
1257 	 */
1258 	r = idn_normalizer_create(&ctx->normalizer);
1259 	if (r != idn_success) {
1260 		ERROR(("libidnkit: cannot create normalizer, %s, line %d\n",
1261 		       idn_result_tostring(r), lineno));
1262 		return (r);
1263 	}
1264 
1265 	r = idn_normalizer_add(ctx->normalizer, argv[0]);
1266 	if (r == idn_invalid_name) {
1267 		ERROR(("libidnkit: unknown normalization scheme \"%-.30s\", "
1268 		       "line %d\n", argv[0], lineno));
1269 		return (r);
1270 	} else if (r != idn_success) {
1271 		return (r);
1272 	}
1273 
1274 	/*
1275 	 * Set prohibit checker.
1276 	 */
1277 	r = idn_checker_create(&ctx->prohibit_checker);
1278 	if (r != idn_success) {
1279 		ERROR(("libidnkit: cannot create prohibit checker, %s, "
1280 		       "line %d\n", idn_result_tostring(r), lineno));
1281 		return (r);
1282 	}
1283 
1284 	sprintf(scheme_name, "%s%s", IDN_CHECKER_PROHIBIT_PREFIX, argv[0]);
1285 	r = idn_checker_add(ctx->prohibit_checker, scheme_name);
1286 	if (r == idn_invalid_name) {
1287 		ERROR(("libidnkit: unknown prohibit scheme \"%-.30s\", "
1288 		       "line %d\n", argv[0], lineno));
1289 		return (r);
1290 	} else if (r != idn_success) {
1291 		return (r);
1292 	}
1293 
1294 	/*
1295 	 * Set unassigned checker.
1296 	 */
1297 	r = idn_checker_create(&ctx->unassigned_checker);
1298 	if (r != idn_success) {
1299 		ERROR(("libidnkit: cannot create unassigned checker, %s, "
1300 		       "line %d\n", idn_result_tostring(r), lineno));
1301 		return (r);
1302 	}
1303 
1304 	sprintf(scheme_name, "%s%s", IDN_CHECKER_UNASSIGNED_PREFIX, argv[0]);
1305 	r = idn_checker_add(ctx->unassigned_checker, scheme_name);
1306 	if (r == idn_invalid_name) {
1307 		ERROR(("libidnkit: unknown unassigned scheme \"%-.30s\", "
1308 		       "line %d\n", argv[0], lineno));
1309 		return (r);
1310 	} else if (r != idn_success) {
1311 		return (r);
1312 	}
1313 
1314 	/*
1315 	 * Set bidi checker.
1316 	 */
1317 	r = idn_checker_create(&ctx->bidi_checker);
1318 	if (r != idn_success) {
1319 		ERROR(("libidnkit: cannot create bidi checker, %s, line %d\n",
1320 		       idn_result_tostring(r), lineno));
1321 		return (r);
1322 	}
1323 
1324 	sprintf(scheme_name, "%s%s", IDN_CHECKER_BIDI_PREFIX, argv[0]);
1325 	r = idn_checker_add(ctx->bidi_checker, scheme_name);
1326 	if (r == idn_invalid_name) {
1327 		ERROR(("libidnkit: unknown bidi scheme \"%-.30s\", "
1328 		       "line %d\n", argv[0], lineno));
1329 		return (r);
1330 	} else if (r != idn_success) {
1331 		return (r);
1332 	}
1333 
1334 	return (idn_success);
1335 }
1336 
1337 static int
1338 split_args(char *s, char **av, int max_ac) {
1339 	int ac;
1340 	int i;
1341 
1342 	for (ac = 0; *s != '\0' && ac < max_ac; ac++) {
1343 		if (ac > 0)
1344 			*s++ = '\0';
1345 		while (isspace((unsigned char)*s))
1346 			s++;
1347 		if (*s == '\0')
1348 			break;
1349 		if (*s == '"' || *s == '\'') {
1350 			int qc = *s++;
1351 			av[ac] = s;
1352 			while (*s != qc) {
1353 				if (*s == '\0')
1354 					return (-1);
1355 				s++;
1356 			}
1357 		} else {
1358 			av[ac] = s;
1359 			while (*s != '\0' && !isspace((unsigned char)*s))
1360 				s++;
1361 		}
1362 	}
1363 
1364 	for (i = ac; i < max_ac; i++)
1365 		av[i] = NULL;
1366 
1367 	return (ac);
1368 }
1369 
1370 static void
1371 resetconf(idn_resconf_t ctx) {
1372 #ifndef WITHOUT_ICONV
1373 	idn_resconf_setlocalconverter(ctx, NULL);
1374 #endif
1375 	idn_resconf_setidnconverter(ctx, NULL);
1376 	idn_resconf_setauxidnconverter(ctx, NULL);
1377 	idn_resconf_setdelimitermap(ctx, NULL);
1378 	idn_resconf_setlocalmapselector(ctx, NULL);
1379 	idn_resconf_setmapper(ctx, NULL);
1380 	idn_resconf_setnormalizer(ctx, NULL);
1381 	idn_resconf_setprohibitchecker(ctx, NULL);
1382 	idn_resconf_setunassignedchecker(ctx, NULL);
1383 	idn_resconf_setbidichecker(ctx, NULL);
1384 }
1385 
1386 #ifndef WITHOUT_ICONV
1387 static idn_result_t
1388 update_local_converter(idn_resconf_t ctx) {
1389 	idn_result_t r;
1390 	const char *old_encoding;
1391 	const char *new_encoding;
1392 
1393 	/*
1394 	 * We don't update local converter, if the converter is set
1395 	 * by idn_resconf_setlocalconverter() or
1396 	 * idn_resconf_setlocalconvertername().
1397 	 */
1398 	if (ctx->local_converter_is_static)
1399 		return (idn_success);
1400 
1401 	/*
1402 	 * Update the local converter if the local encoding is changed.
1403 	 */
1404 	old_encoding = (ctx->local_converter != NULL) ?
1405 		       idn_converter_localencoding(ctx->local_converter) :
1406 		       NULL;
1407 	new_encoding = idn_localencoding_name();
1408 	if (new_encoding == NULL) {
1409 		ERROR(("cannot determine local codeset name\n"));
1410 		return (idn_notfound);
1411 	}
1412 
1413 	if (old_encoding != NULL &&
1414 	    new_encoding != NULL &&
1415 	    strcmp(old_encoding, new_encoding) == 0) {
1416 		return (idn_success);
1417 	}
1418 
1419 	if (ctx->local_converter != NULL) {
1420 		idn_converter_destroy(ctx->local_converter);
1421 		ctx->local_converter = NULL;
1422 	}
1423 
1424 	r = idn_converter_create(new_encoding,
1425 				 &ctx->local_converter,
1426 				 IDN_CONVERTER_RTCHECK);
1427 	return (r);
1428 }
1429 #endif
1430 
1431 idn_result_t
1432 idn_resconf_setdefaults(idn_resconf_t ctx)
1433 {
1434 	idn_result_t r;
1435 
1436 	assert(ctx != NULL);
1437 
1438 	TRACE(("idn_resconf_setdefaults()\n"));
1439 
1440 	resetconf(ctx);
1441 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
1442 	if (r != idn_success) {
1443 		ERROR(("libidnkit: cannot create delimiter mapper, %s\n",
1444 		       idn_result_tostring(r)));
1445 		return (r);
1446 	}
1447 
1448 	return setdefaults_body(ctx, 0);
1449 }
1450 
1451 static idn_result_t
1452 setdefaults_body(idn_resconf_t ctx, int conf_mask) {
1453 	idn_result_t r;
1454 
1455 	TRACE(("setdefaults_body()\n"));
1456 	assert(ctx != NULL);
1457 
1458 	if (!(conf_mask & DEFAULT_CONF_NAMEPREP)) {
1459 		TRACE(("set default nameprep\n"));
1460 		r = idn_resconf_setnameprepversion(ctx, IDN_NAMEPREP_CURRENT);
1461 		if (r != idn_success) {
1462 			return (r);
1463 		}
1464 	}
1465 	if (!(conf_mask & DEFAULT_CONF_IDN_ENCODING)) {
1466 		TRACE(("set default idn encoding\n"));
1467 		r = idn_converter_create(IDN_ENCODING_CURRENT,
1468 					 &ctx->idn_converter,
1469 					 IDN_CONVERTER_DELAYEDOPEN |
1470 					 IDN_CONVERTER_RTCHECK);
1471 		if (r != idn_success) {
1472 			ERROR(("libidnkit: cannot create idn converter, %s\n",
1473 			       idn_result_tostring(r)));
1474 			return (r);
1475 		}
1476 	}
1477 
1478 	return (idn_success);
1479 }
1480