1 /*
2 * TERMS AND CONDITIONS
3 * FOR
4 * OPEN SOURCE CODE LICENSE
5 * Version 1.1
6 *
7 * Japan Registry Services Co., Ltd. ("JPRS"), a Japanese corporation
8 * having its head office at Chiyoda First Bldg. East 13F 3-8-1 Nishi-Kanda,
9 * Chiyoda-ku, Tokyo 101-0065, Japan, grants you the license for open source
10 * code specified in EXHIBIT A the "Code" subject to the following Terms and
11 * Conditions ("OSCL").
12 *
13 * 1. License Grant.
14 * JPRS hereby grants you a worldwide, royalty-free, non-exclusive
15 * license, subject to third party intellectual property claims:
16 * (a) under intellectual property rights (other than patent or
17 * trademark) licensable by JPRS to use, reproduce, modify, display,
18 * perform, sublicense and distribute the Code (or portions thereof)
19 * with or without modifications, and/or as part of a derivative work;
20 * or
21 * (b) under claims of the infringement through the making, using,
22 * offering to sell and/or otherwise disposing the JPRS Revised Code
23 * (or portions thereof);
24 * (c) the licenses granted in this Section 1(a) and (b) are effective on
25 * the date JPRS first distributes the Code to you under the terms of
26 * this OSCL;
27 * (d) Notwithstanding the above stated terms, no patent license is
28 * granted:
29 * 1) for a code that you delete from the Code;
30 * 2) separate from the Code; or
31 * 3) for infringements caused by:
32 * i) modification of the Code; or
33 * ii) combination of the Code with other software or devices.
34 *
35 * 2. Consents.
36 * You agree that:
37 * (a) you must include a copy of this OSCL and the notice set forth in
38 * EXHIBIT A with every copy of the Code you distribute;
39 * (b) you must include a copy of this OSCL and the notice set forth in
40 * EXHIBIT A with every copy of binary form of the Code in the
41 * documentation and/or other materials provided with the distribution;
42 * (c) you may not offer or impose any terms on any source code version
43 * that alters or restricts the applicable version of this OSCL or
44 * the recipients' rights hereunder.
45 * (d) If the terms and conditions are set forth in EXHIBIT A, you must
46 * comply with those terms and conditions.
47 *
48 * 3. Proprietary Information.
49 * All trademarks, service marks, patents, copyrights, trade secrets, and
50 * other proprietary rights in or related to the Code are and will remain
51 * the exclusive property of JPRS or its licensors, whether or not
52 * specifically recognized or perfected under local law except specified
53 * in this OSCL; provided however you agree and understand that the JPRS
54 * name may not be used to endorse or promote this Code without prior
55 * written approval of JPRS.
56 *
57 * 4. WARRANTY DISCLAIMER.
58 * JPRS MAKES NO REPRESENTATIONS AND WARRANTIES REGARDING THE USE OF THE
59 * CODE, NOR DOES JPRS MAKE ANY REPRESENTATIONS THAT THE CODE WILL BECOME
60 * COMMERCIALLY AVAILABLE. JPRS, ITS AFFILIATES, AND ITS SUPPLIERS DO NOT
61 * WARRANT OR REPRESENT THAT THE CODE IS FREE OF ERRORS OR THAT THE CODE
62 * IS SUITABLE FOR TRANSLATION AND/OR LOCALIZATION. THE CODE IS PROVIDED
63 * ON AN "AS IS" BASIS AND JPRS AND ITS SUPPLIERS HAVE NO OBLIGATION TO
64 * CORRECT ERRORS OR TO SUPPORT THE CODE UNDER THIS OSCL FOR ANY REASON.
65 * TO THE FULL EXTENT PERMITTED BY LAW, ALL OBLIGATIONS ARE HEREBY
66 * EXCLUDED WHETHER EXPRESS, STATUTORY OR IMPLIED UNDER LAW, COURSE OF
67 * DEALING, CUSTOM, TRADE USAGE, ORAL OR WRITTEN STATEMENT OR OTHERWISE,
68 * INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY
69 * OR FITNESS FOR A PARTICULAR PURPOSE CONCERNING THE CODE.
70 *
71 * 5. NO LIABILITY.
72 * UNDER NO CIRCUMSTANCES SHALL JPRS AND/OR ITS AFFILIATES, LICENSORS, OR
73 * REPRESENTATIVES BE LIABLE FOR ANY DAMAGES INCLUDING BUT NOT LIMITED TO
74 * CONSEQUENTIAL, INDIRECT, SPECIAL, PUNITIVE OR INCIDENTAL DAMAGES,
75 * WHETHER FORESEEABLE OR UNFORESEEABLE, BASED ON YOUR CLAIMS, INCLUDING,
76 * BUT NOT LIMITED TO, CLAIMS FOR LOSS OF DATA, GOODWILL, PROFITS, USE OF
77 * MONEY, INTERRUPTION IN USE OR AVAILABILITY OF DATA, STOPPAGE, IMPLIED
78 * WARRANTY, BREACH OF CONTRACT, MISREPRESENTATION, NEGLIGENCE, STRICT
79 * LIABILITY IN TORT, OR OTHERWISE.
80 *
81 * 6. Indemnification.
82 * You hereby agree to indemnify, defend, and hold harmless JPRS for any
83 * liability incurred by JRPS due to your terms of warranty, support,
84 * indemnity, or liability offered by you to any third party.
85 *
86 * 7. Termination.
87 * 7.1 This OSCL shall be automatically terminated in the events that:
88 * (a) You fail to comply with the terms herein and fail to cure such
89 * breach within 30 days of becoming aware of the breach;
90 * (b) You initiate patent or copyright infringement litigation against
91 * any party (including a cross-claim or counterclaim in a lawsuit)
92 * alleging that the Code constitutes a direct or indirect patent or
93 * copyright infringement, in such case, this OSCL to you shall
94 * terminate as of the date such litigation is filed;
95 * 7.2 In the event of termination under Sections 7.1(a) or 7.1(b) above,
96 * all end user license agreements (excluding distributors and
97 * resellers) which have been validly granted by You or any distributor
98 * hereunder prior to termination shall survive termination.
99 *
100 *
101 * 8. General.
102 * This OSCL shall be governed by, and construed and enforced in
103 * accordance with, the laws of Japan. Any litigation or arbitration
104 * between the parties shall be conducted exclusively in Tokyo, Japan
105 * except written consent of JPRS provides other venue.
106 *
107 *
108 * EXHIBIT A
109 *
110 * The original open source code of idnkit-2 is idnkit-1.0 developed and
111 * conceived by Japan Network Information Center ("JPNIC"), a Japanese
112 * association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
113 * Chiyoda-ku, Tokyo 101-0047, Japan, and JPRS modifies above original code
114 * under following Terms and Conditions set forth by JPNIC.
115 *
116 * JPNIC
117 *
118 * Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved.
119 *
120 * By using this file, you agree to the terms and conditions set forth bellow.
121 *
122 * LICENSE TERMS AND CONDITIONS
123 *
124 * The following License Terms and Conditions apply, unless a different
125 * license is obtained from Japan Network Information Center ("JPNIC"),
126 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
127 * Chiyoda-ku, Tokyo 101-0047, Japan.
128 *
129 * 1. Use, Modification and Redistribution (including distribution of any
130 * modified or derived work) in source and/or binary forms is permitted
131 * under this License Terms and Conditions.
132 *
133 * 2. Redistribution of source code must retain the copyright notices as they
134 * appear in each source code file, this License Terms and Conditions.
135 *
136 * 3. Redistribution in binary form must reproduce the Copyright Notice,
137 * this License Terms and Conditions, in the documentation and/or other
138 * materials provided with the distribution. For the purposes of binary
139 * distribution the "Copyright Notice" refers to the following language:
140 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
141 *
142 * 4. The name of JPNIC may not be used to endorse or promote products
143 * derived from this Software without specific prior written approval of
144 * JPNIC.
145 *
146 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
147 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
148 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
149 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
150 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
151 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
152 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
153 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
154 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
155 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
156 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
157 *
158 *
159 * JPRS Public License Notice
160 * For
161 * idnkit-2.
162 *
163 * The contents of this file are subject to the Terms and Conditions for
164 * the Open Source Code License (the "OSCL"). You may not use this file
165 * except in compliance with above terms and conditions. A copy of the OSCL
166 * is available at <http://jprs.co.jp/idn/>.
167 * The JPRS Revised Code is idnkit-2.
168 * The Initial Developer of the JPRS Revised Code is Japan Network
169 * Information Center ("JPNIC"), a Japanese association,
170 * Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, Chiyoda-ku, Tokyo
171 * 101-0047, Japan.
172 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
173 * "Copyright (c) 2010-2012 Japan Registry Services Co., Ltd. All rights reserved."
174 * Contributor(s): ______________________________________.
175 *
176 * If you wish to allow use of your version of this file only under the
177 * above License(s) and not to allow others to use your version of this
178 * file, please indicate your decision by deleting the relevant provisions
179 * above and replacing them with the notice and other provisions required
180 * by the above License(s). If you do not delete the relevant provisions,
181 * a recipient may use your version of this file under either the above
182 * License(s).
183 */
184
185 #include <config.h>
186
187 #include <stddef.h>
188 #include <stdlib.h>
189 #include <string.h>
190
191 #include <idn/assert.h>
192 #include <idn/debug.h>
193 #include <idn/logmacro.h>
194 #include <idn/result.h>
195 #include <idn/res.h>
196 #include <idn/res_internal.h>
197 #include <idn/labellist.h>
198 #include <idn/punycode.h>
199 #include <idn/utf32.h>
200 #include <idn/utf8.h>
201 #include <idn/util.h>
202
203 #define ENCODE_MASK \
204 (IDN_UNICODECONV | IDN_MAP | IDN_ASCLOWER | IDN_RTCONV | \
205 IDN_PROHCHECK | IDN_UNASCHECK | IDN_NFCCHECK | IDN_PREFCHECK | \
206 IDN_HYPHCHECK | IDN_COMBCHECK | IDN_CTXJCHECK | IDN_CTXOCHECK | \
207 IDN_CTXOLITECHECK | IDN_BIDICHECK | IDN_LOCALCHECK | IDN_IDNCONV | \
208 IDN_LENCHECK | IDN_RTCHECK | IDN_LOCALCONV | IDN_LITEFORCEUTF8 | \
209 IDN_UNDOIFERR)
210
211 #define DECODE_MASK \
212 (IDN_UNICODECONV | IDN_MAP | IDN_ASCLOWER | IDN_IDNCONV | \
213 IDN_PROHCHECK | IDN_UNASCHECK | IDN_NFCCHECK | IDN_PREFCHECK | \
214 IDN_HYPHCHECK | IDN_COMBCHECK | IDN_CTXJCHECK | IDN_CTXOCHECK | \
215 IDN_CTXOLITECHECK | IDN_BIDICHECK | IDN_LOCALCHECK | IDN_RTCHECK | \
216 IDN_LOCALCONV | IDN_LITEFORCEUTF8 | IDN_UNDOIFERR)
217
218 static int have_rtl_label(idn_resconf_t ctx,
219 idn__labellist_t labellist);
220 static int is_ldh_label(idn__labellist_t label);
221
222 #ifdef LIBIDNKITLITE
223 static const int is_idnkitlite = 1;
224 #else
225 static const int is_idnkitlite = 0;
226 #endif
227
228 /*
229 * Encode a domain name.
230 */
231 idn_result_t
idn_res_encodename(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen)232 idn_res_encodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
233 char *to, size_t tolen) {
234 idn_result_t r = idn_success;
235 char actions_string[ACTION_STRING_BUFSIE];
236 char *utf8_from = NULL;
237 unsigned long *utf32_from = NULL;
238 unsigned long *utf32_to = NULL;
239 char *utf8_to = NULL;
240 idn__labellist_t labels = NULL, l;
241 int have_rtl;
242
243 assert(ctx != NULL && from != NULL && to != NULL);
244
245 idn__res_actionstostring(actions, actions_string);
246 TRACE(("idn_res_encodename(actions=%s, from=\"%s\", tolen=%d)\n",
247 actions_string, idn__debug_xstring(from), (int)tolen));
248
249 if (actions & ~ENCODE_MASK) {
250 WARNING(("idn_res_encodename: invalid actions 0x%x\n",
251 actions));
252 r = idn_invalid_action;
253 goto ret;
254 }
255
256 if (is_idnkitlite && actions & IDN_LITEFORCEUTF8)
257 actions &= ~(IDN_LOCALCONV | IDN_UNICODECONV);
258
259 /*
260 * Convert `from' to UTF-32.
261 */
262 if (actions & IDN_UNICODECONV)
263 r = idn__res_unicodeconv(ctx, from, &utf8_from);
264 else {
265 utf8_from = idn__util_strdup(from);
266 r = (utf8_from != NULL) ? idn_success : idn_nomemory;
267 }
268 if (r != idn_success)
269 goto ret;
270
271 r = idn__res_utf8toutf32(ctx, utf8_from, &utf32_from);
272 if (r != idn_success)
273 goto ret;
274
275 /*
276 * Map.
277 */
278 if (actions & IDN_MAP) {
279 unsigned long *tmp_from;
280
281 r = idn__res_map(ctx, utf32_from, &tmp_from);
282 if (r != idn_success)
283 goto ret;
284 free(utf32_from);
285 utf32_from = tmp_from;
286 }
287
288 /*
289 * Split the name into a list of labels.
290 */
291 if ((utf32_from[0] == '\0') ||
292 (utf32_from[0] == '.' && utf32_from[1] == '\0')) {
293 utf32_to = idn__utf32_strdup(utf32_from);
294 if (utf32_to == NULL)
295 r = idn_nomemory;
296 } else {
297 r = idn__labellist_create(utf32_from, &labels);
298 }
299 if (r != idn_success)
300 goto ret;
301
302 /*
303 * Perform conversions and tests.
304 */
305 for (l = labels; l != NULL; l = idn__labellist_next(l)) {
306 do {
307 int is_xn;
308 int is_ldh;
309
310 if (actions & IDN_ASCLOWER) {
311 r = idn__res_asclower(ctx, l);
312 if (r != idn_success)
313 break;
314 }
315
316 is_xn = idn__punycode_isacelabel(idn__labellist_getname(l));
317 r = idn__labellist_setundoname(l);
318 if (r != idn_success)
319 break;
320
321 if ((actions & IDN_RTCONV) && is_xn) {
322 r = idn__labellist_setroundtripname(l);
323 if (r != idn_success)
324 break;
325 r = idn__res_idnconv_decode(ctx, l);
326 if (r != idn_success)
327 break;
328 }
329
330 is_ldh = is_ldh_label(l);
331
332 if ((actions & IDN_PROHCHECK) && !is_ldh) {
333 r = idn__res_prohcheck(ctx, l);
334 if (r != idn_success)
335 break;
336 }
337 if ((actions & IDN_UNASCHECK) && !is_ldh) {
338 r = idn__res_unascheck(ctx, l);
339 if (r != idn_success)
340 break;
341 }
342 if ((actions & IDN_NFCCHECK) && !is_ldh) {
343 r = idn__res_nfccheck(ctx, l);
344 if (r != idn_success)
345 break;
346 }
347 if ((actions & IDN_PREFCHECK) && !is_ldh) {
348 r = idn__res_prefcheck(ctx, l);
349 if (r != idn_success)
350 break;
351 }
352 if (actions & IDN_HYPHCHECK) {
353 r = idn__res_hyphcheck(ctx, l);
354 if (r != idn_success)
355 break;
356 }
357 if ((actions & IDN_COMBCHECK) && !is_ldh) {
358 r = idn__res_combcheck(ctx, l);
359 if (r != idn_success)
360 break;
361 }
362 if ((actions & IDN_CTXJCHECK) && !is_ldh) {
363 r = idn__res_ctxjcheck(ctx, l);
364 if (r != idn_success)
365 break;
366 }
367 if ((actions & IDN_CTXOCHECK) && !is_ldh) {
368 r = idn__res_ctxocheck(ctx, l);
369 if (r != idn_success)
370 break;
371 }
372 if ((actions & IDN_CTXOLITECHECK) && !is_ldh) {
373 r = idn__res_ctxolitecheck(ctx, l);
374 if (r != idn_success)
375 break;
376 }
377 } while (0);
378
379 if (r != idn_success && r != idn_nomemory &&
380 actions & IDN_UNDOIFERR) {
381 r = idn__labellist_undo(l);
382 if (r != idn_success)
383 goto ret;
384 TRACE(("idn_res_encodename(): undo (label=\"%s\")\n",
385 idn__debug_utf32xstring(idn__labellist_getname(l))));
386 continue;
387 }
388 if (r != idn_success)
389 goto ret;
390 }
391
392 have_rtl = have_rtl_label(ctx, labels);
393 for (l = labels; l != NULL; l = idn__labellist_next(l)) {
394 int is_xn = idn__punycode_isacelabel(idn__labellist_getroundtripname(l));
395 int is_ldh = is_ldh_label(l);
396
397 if (idn__labellist_getundocount(l) > 0)
398 continue;
399
400 do {
401 if ((actions & IDN_BIDICHECK) && have_rtl) {
402 r = idn__res_bidicheck(ctx, l);
403 if (r != idn_success)
404 break;
405 }
406 if (actions & IDN_LOCALCHECK) {
407 r = idn__res_localcheck(ctx, l);
408 if (r != idn_success)
409 break;
410 }
411 if (actions & IDN_IDNCONV && !is_ldh) {
412 r = idn__res_idnconv_encode(ctx, l);
413 if (r != idn_success)
414 break;
415 }
416 if (actions & IDN_LENCHECK) {
417 r = idn__res_lencheck(ctx, l);
418 if (r != idn_success)
419 break;
420 }
421 if ((actions & IDN_RTCHECK) && is_xn) {
422 r = idn__res_rtcheck_encode(ctx, l);
423 if (r != idn_success)
424 break;
425 }
426 } while (0);
427
428 if (r != idn_success && r != idn_nomemory &&
429 actions & IDN_UNDOIFERR) {
430 r = idn__labellist_undo(l);
431 if (r != idn_success)
432 goto ret;
433 TRACE(("idn_res_encodename(): undo (label=\"%s\")\n",
434 idn__debug_utf32xstring(idn__labellist_getname(l))));
435 continue;
436 }
437 if (r != idn_success)
438 goto ret;
439 }
440
441 /*
442 * Join labels.
443 */
444 if (labels != NULL) {
445 r = idn__res_joinlabels(ctx, labels, &utf32_to);
446 if (r != idn_success)
447 goto ret;
448 }
449
450 r = idn__res_utf32toutf8(ctx, utf32_to, &utf8_to);
451 if (r != idn_success)
452 goto ret;
453
454 /*
455 * Perform IDN_LOCALCONV.
456 */
457 if (actions & IDN_LOCALCONV)
458 r = idn__res_localconv(ctx, utf8_to, to, tolen);
459 else
460 r = idn__util_strcpy(to, tolen, utf8_to);
461
462 ret:
463 if (r == idn_success) {
464 TRACE(("idn_res_encodename(): success (to=\"%s\")\n",
465 idn__debug_xstring(to)));
466 } else {
467 TRACE(("idn_res_encodename(): %s\n", idn_result_tostring(r)));
468 }
469 free(utf8_to);
470 free(utf32_to);
471 free(utf32_from);
472 free(utf8_from);
473 if (labels != NULL)
474 idn__labellist_destroy(labels);
475 return (r);
476 }
477
478 /*
479 * Decode a domain name.
480 */
481 idn_result_t
idn_res_decodename(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen)482 idn_res_decodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
483 char *to, size_t tolen) {
484 idn_result_t r = idn_success;
485 char actions_string[ACTION_STRING_BUFSIE];
486 char *utf8_from = NULL;
487 unsigned long *utf32_from = NULL;
488 unsigned long *utf32_to = NULL;
489 char *utf8_to = NULL;
490 idn__labellist_t labels = NULL, l;
491 int have_rtl;
492
493 assert(ctx != NULL && from != NULL && to != NULL);
494
495 idn__res_actionstostring(actions, actions_string);
496 TRACE(("idn_res_decodename(actions=%s, from=\"%s\", tolen=%d)\n",
497 actions_string, idn__debug_xstring(from), (int)tolen));
498
499 if (actions & ~DECODE_MASK) {
500 WARNING(("idn_res_decodename: invalid actions 0x%x\n",
501 actions));
502 r = idn_invalid_action;
503 goto ret;
504 }
505
506 if (is_idnkitlite && actions & IDN_LITEFORCEUTF8)
507 actions &= ~(IDN_LOCALCONV | IDN_UNICODECONV);
508
509 /*
510 * Convert `from' to UTF-32.
511 */
512 if (actions & IDN_UNICODECONV)
513 r = idn__res_unicodeconv(ctx, from, &utf8_from);
514 else {
515 utf8_from = idn__util_strdup(from);
516 r = (utf8_from != NULL) ? idn_success : idn_nomemory;
517 }
518 if (r != idn_success)
519 goto ret;
520
521 r = idn__res_utf8toutf32(ctx, utf8_from, &utf32_from);
522 if (r != idn_success)
523 goto ret;
524
525 /*
526 * Map.
527 */
528 if (actions & IDN_MAP) {
529 unsigned long *tmp_from;
530
531 r = idn__res_map(ctx, utf32_from, &tmp_from);
532 if (r != idn_success)
533 goto ret;
534 free(utf32_from);
535 utf32_from = tmp_from;
536 }
537
538 /*
539 * Split the name into a list of labels.
540 */
541 if ((utf32_from[0] == '\0') ||
542 (utf32_from[0] == '.' && utf32_from[1] == '\0')) {
543 utf32_to = idn__utf32_strdup(utf32_from);
544 if (utf32_to == NULL)
545 r = idn_nomemory;
546 } else {
547 r = idn__labellist_create(utf32_from, &labels);
548 }
549 if (r != idn_success)
550 goto ret;
551
552 /*
553 * Perform conversions and tests.
554 */
555 for (l = labels; l != NULL; l = idn__labellist_next(l)) {
556 do {
557 int is_xn;
558 int is_ldh;
559
560 if (actions & IDN_ASCLOWER) {
561 r = idn__res_asclower(ctx, l);
562 if (r != idn_success)
563 break;
564 }
565
566 is_xn = idn__punycode_isacelabel(idn__labellist_getname(l));
567 r = idn__labellist_setundoname(l);
568 if (r != idn_success)
569 break;
570
571 if ((actions & IDN_IDNCONV) && is_xn) {
572 r = idn__labellist_setroundtripname(l);
573 if (r != idn_success)
574 break;
575 r = idn__res_idnconv_decode(ctx, l);
576 if (r != idn_success)
577 break;
578 }
579
580 is_ldh = is_ldh_label(l);
581
582 if ((actions & IDN_PROHCHECK) && !is_ldh) {
583 r = idn__res_prohcheck(ctx, l);
584 if (r != idn_success)
585 break;
586 }
587 if ((actions & IDN_UNASCHECK) && !is_ldh) {
588 r = idn__res_unascheck(ctx, l);
589 if (r != idn_success)
590 break;
591 }
592 if ((actions & IDN_NFCCHECK) && !is_ldh) {
593 r = idn__res_nfccheck(ctx, l);
594 if (r != idn_success)
595 break;
596 }
597 if ((actions & IDN_PREFCHECK) && !is_ldh) {
598 r = idn__res_prefcheck(ctx, l);
599 if (r != idn_success)
600 break;
601 }
602 if (actions & IDN_HYPHCHECK) {
603 r = idn__res_hyphcheck(ctx, l);
604 if (r != idn_success)
605 break;
606 }
607 if ((actions & IDN_COMBCHECK) && !is_ldh) {
608 r = idn__res_combcheck(ctx, l);
609 if (r != idn_success)
610 break;
611 }
612 if ((actions & IDN_CTXJCHECK) && !is_ldh) {
613 r = idn__res_ctxjcheck(ctx, l);
614 if (r != idn_success)
615 break;
616 }
617 if ((actions & IDN_CTXOCHECK) && !is_ldh) {
618 r = idn__res_ctxocheck(ctx, l);
619 if (r != idn_success)
620 break;
621 }
622 if ((actions & IDN_CTXOLITECHECK) && !is_ldh) {
623 r = idn__res_ctxolitecheck(ctx, l);
624 if (r != idn_success)
625 break;
626 }
627 } while (0);
628
629 if (r != idn_success && r != idn_nomemory &&
630 actions & IDN_UNDOIFERR) {
631 r = idn__labellist_undo(l);
632 if (r != idn_success)
633 goto ret;
634 TRACE(("idn_res_decodename(): undo (label=\"%s\")\n",
635 idn__debug_utf32xstring(idn__labellist_getname(l))));
636 continue;
637 }
638 if (r != idn_success)
639 goto ret;
640 }
641
642 have_rtl = have_rtl_label(ctx, labels);
643 for (l = labels; l != NULL; l = idn__labellist_next(l)) {
644 int is_xn = idn__punycode_isacelabel(idn__labellist_getroundtripname(l));
645
646 do {
647 if ((actions & IDN_BIDICHECK) && have_rtl) {
648 r = idn__res_bidicheck(ctx, l);
649 if (r != idn_success)
650 break;
651 }
652 if (actions & IDN_LOCALCHECK) {
653 r = idn__res_localcheck(ctx, l);
654 if (r != idn_success)
655 break;
656 }
657 if ((actions & IDN_RTCHECK) && is_xn) {
658 r = idn__res_rtcheck_decode(ctx, l);
659 if (r != idn_success)
660 break;
661 }
662 } while (0);
663
664 if (r != idn_success && r != idn_nomemory &&
665 actions & IDN_UNDOIFERR) {
666 r = idn__labellist_undo(l);
667 if (r != idn_success)
668 goto ret;
669 TRACE(("idn_res_decodename(): undo (label=\"%s\")\n",
670 idn__debug_utf32xstring(idn__labellist_getname(l))));
671 continue;
672 }
673 if (r != idn_success)
674 goto ret;
675 }
676
677 /*
678 * Join labels.
679 */
680 if (labels != NULL) {
681 r = idn__res_joinlabels(ctx, labels, &utf32_to);
682 if (r != idn_success)
683 goto ret;
684 }
685
686 r = idn__res_utf32toutf8(ctx, utf32_to, &utf8_to);
687 if (r != idn_success)
688 goto ret;
689
690 /*
691 * Perform IDN_LOCALCONV.
692 */
693 if (actions & IDN_LOCALCONV)
694 r = idn__res_localconv(ctx, utf8_to, to, tolen);
695 else
696 r = idn__util_strcpy(to, tolen, utf8_to);
697
698 ret:
699 if (r == idn_success) {
700 TRACE(("idn_res_decodename(): success (to=\"%s\")\n",
701 idn__debug_xstring(to)));
702 } else {
703 TRACE(("idn_res_decodename(): %s\n", idn_result_tostring(r)));
704 }
705 free(utf8_to);
706 free(utf32_to);
707 free(utf32_from);
708 free(utf8_from);
709 if (labels != NULL)
710 idn__labellist_destroy(labels);
711 return (r);
712 }
713
714 /*
715 * Decode a domain name auxiliary encoding support.
716 */
717 idn_result_t
idn_res_decodename2(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen,const char * auxencoding)718 idn_res_decodename2(idn_resconf_t ctx, idn_action_t actions, const char *from,
719 char *to, size_t tolen, const char *auxencoding) {
720 idn_result_t r = idn_success;
721 char actions_string[ACTION_STRING_BUFSIE];
722 idn_resconf_t auxctx = NULL;
723 char *utf8_from = NULL;
724
725 assert(ctx != NULL && from != NULL && to != NULL);
726
727 idn__res_actionstostring(actions, actions_string);
728 TRACE(("idn_res_decodename2(actions=%s, from=\"%s\", tolen=%d, "
729 "auxencoding=\"%s\")\n",
730 actions_string, idn__debug_xstring(from), (int)tolen,
731 idn__debug_xstring(auxencoding)));
732
733 if (auxencoding == NULL)
734 auxencoding = IDN__UTF8_ENCODINGNAME;
735
736 /*
737 * Convert `from' to UTF-8.
738 */
739 r = idn_resconf_create(&auxctx);
740 if (r != idn_success)
741 goto ret;
742 r = idn_resconf_setlocalencoding(auxctx, auxencoding);
743 if (r != idn_success)
744 goto ret;
745 r = idn__res_unicodeconv(auxctx, from, &utf8_from);
746 if (r != idn_success)
747 goto ret;
748
749 r = idn_res_decodename(ctx, actions & ~IDN_UNICODECONV, utf8_from,
750 to, tolen);
751
752 ret:
753 if (r == idn_success) {
754 TRACE(("idn_res_decodename2(): success (to=\"%s\")\n",
755 idn__debug_xstring(to)));
756 } else {
757 TRACE(("idn_res_decodename2(): %s\n", idn_result_tostring(r)));
758 }
759
760 free(utf8_from);
761 if (auxctx != NULL)
762 idn_resconf_destroy(auxctx);
763
764 return (r);
765 }
766
767 /*
768 * Compare two domain names.
769 */
770 idn_result_t
idn_res_comparenames(idn_resconf_t ctx,idn_action_t actions,const char * name1,const char * name2)771 idn_res_comparenames(idn_resconf_t ctx, idn_action_t actions,
772 const char *name1, const char *name2) {
773 return (idn_res_comparenames2(ctx, actions, name1, actions, name2));
774 }
775
776 idn_result_t
idn_res_comparenames2(idn_resconf_t ctx,idn_action_t actions1,const char * name1,idn_action_t actions2,const char * name2)777 idn_res_comparenames2(idn_resconf_t ctx,
778 idn_action_t actions1, const char *name1,
779 idn_action_t actions2, const char *name2) {
780 idn_result_t r = idn_success;
781 char actions1_string[ACTION_STRING_BUFSIE];
782 char actions2_string[ACTION_STRING_BUFSIE];
783 char *to1 = NULL;
784 char *to2 = NULL;
785 size_t tolen1 = 256; /* may be large enough. */
786 size_t tolen2 = 256; /* may be large enough. */
787
788 assert(ctx != NULL && name1 != NULL && name2 != NULL);
789
790 idn__res_actionstostring(actions1, actions1_string);
791 idn__res_actionstostring(actions2, actions2_string);
792 TRACE(("idn_res_comparenames2(actions1=%s, name1=\"%s\", "
793 "actions2=%s, name2=\"%s\")\n",
794 actions1_string, idn__debug_xstring(name1),
795 actions2_string, idn__debug_xstring(name2)));
796
797 for (;;) {
798 void *new_to1;
799
800 new_to1 = realloc(to1, sizeof(*to1) * tolen1);
801 if (new_to1 == NULL) {
802 r = idn_nomemory;
803 goto ret;
804 }
805 to1 = (char *)new_to1;
806 r = idn_res_encodename(ctx, actions1, name1, to1, tolen1);
807 if (r == idn_success)
808 break;
809 else if (r != idn_buffer_overflow)
810 goto ret;
811 tolen1 *= 2;
812 }
813
814 for (;;) {
815 void *new_to2;
816
817 new_to2 = realloc(to2, sizeof(*to2) * tolen2);
818 if (new_to2 == NULL) {
819 r = idn_nomemory;
820 goto ret;
821 }
822 to2 = (char *)new_to2;
823 r = idn_res_encodename(ctx, actions2, name2, to2, tolen2);
824 if (r == idn_success)
825 break;
826 else if (r != idn_buffer_overflow)
827 goto ret;
828 tolen2 *= 2;
829 }
830
831 r = (idn__util_strcasecmp(to1, to2) == 0) ? idn_success : idn_neq;
832
833 ret:
834 if (r == idn_success) {
835 TRACE(("idn_res_comparenames2(): success "
836 "(name1=name2=\"%s\")\n",
837 idn__debug_xstring(to1)));
838 } else if (r == idn_neq) {
839 TRACE(("idn_res_comparenames2(): neq "
840 "(name1=\"%s\" <=> name2=\"%s\")\n",
841 idn__debug_xstring(to1),
842 idn__debug_xstring(to2)));
843 } else {
844 TRACE(("idn_res_comparenames2(): %s\n",
845 idn_result_tostring(r)));
846 }
847 free(to1);
848 free(to2);
849
850 return (r);
851 }
852
853 idn_result_t
idn_res_checkname(idn_resconf_t ctx,idn_action_t actions,const char * name)854 idn_res_checkname(idn_resconf_t ctx, idn_action_t actions, const char *name) {
855 idn_result_t r = idn_success;
856 char actions_string[ACTION_STRING_BUFSIE];
857 char *to = NULL;
858 size_t tolen = 256; /* may be large enough. */
859
860 assert(ctx != NULL && name != NULL);
861
862 idn__res_actionstostring(actions, actions_string);
863 TRACE(("idn_res_checkname(actions=%s, name=\"%s\")\n",
864 actions_string, idn__debug_xstring(name)));
865
866 for (;;) {
867 void *new_to;
868
869 new_to = realloc(to, sizeof(*to) * tolen);
870 if (new_to == NULL) {
871 r = idn_nomemory;
872 goto ret;
873 }
874 to = (char *)new_to;
875 r = idn_res_encodename(ctx, actions, name, to, tolen);
876 if (r == idn_success)
877 break;
878 else if (r != idn_buffer_overflow)
879 goto ret;
880 tolen *= 2;
881 }
882
883 ret:
884 if (r == idn_success) {
885 TRACE(("idn_res_checkname(): success (name=\"%s\")\n",
886 idn__debug_xstring(to)));
887 } else {
888 TRACE(("idn_res_checkname(): %s\n", idn_result_tostring(r)));
889 }
890 free(to);
891
892 return (r);
893 }
894
895 /*
896 * Check if 'labellist' has at least one RTL label.
897 */
898 static int
have_rtl_label(idn_resconf_t ctx,idn__labellist_t labellist)899 have_rtl_label(idn_resconf_t ctx, idn__labellist_t labellist) {
900 idn__labellist_t l;
901
902 for (l = labellist; l != NULL; l = idn__labellist_next(l)) {
903 if (idn__res_isrtllabel(ctx, l))
904 return (1);
905 }
906
907 return (0);
908 }
909
910 /*
911 * Check if 'label' is an LDH label.
912 */
913 static int
is_ldh_label(idn__labellist_t label)914 is_ldh_label(idn__labellist_t label) {
915 const unsigned long *l;
916
917 l = idn__labellist_getname(label);
918 if (l == NULL)
919 return (1);
920
921 while (*l != '\0') {
922 if (!('A' <= *l && *l <= 'Z') &&
923 !('a' <= *l && *l <= 'z') &&
924 !('0' <= *l && *l <= '9') &&
925 *l != '-') {
926 return (0);
927 }
928 l++;
929 }
930
931 return (1);
932 }
933
934 /*
935 * Convert 'actions' to a string.
936 */
937 struct action_name_table {
938 idn_action_t action;
939 char *name;
940 };
941
942 static const struct action_name_table
943 combined_action_name_table[] = {
944 {IDN_DECODE_REGIST, "DECODE_REGIST"},
945 {IDN_DECODE_LOOKUP, "DECODE_LOOKUP"},
946 {IDN_ENCODE_REGIST, "ENCODE_REGIST"},
947 {IDN_ENCODE_LOOKUP, "ENCODE_LOOKUP"},
948 {IDN_COMPARE_REGIST, "COMPARE_REGIST"},
949 {IDN_COMPARE_LOOKUP, "COMPARE_LOOKUP"},
950 {IDN_CHECK_REGIST, "CHECK_REGIST"},
951 {IDN_CHECK_LOOKUP, "CHECK_LOOKUP"},
952 {0, NULL}
953 };
954
955 static const struct action_name_table
956 single_action_name_table[] = {
957 {IDN_UNICODECONV, "UNICODECONV"},
958 {IDN_MAP, "MAP"},
959 {IDN_ASCLOWER, "ASCLOWER"},
960 {IDN_RTCONV, "RTCONV"},
961 {IDN_PROHCHECK, "PROHCHECK"},
962 {IDN_UNASCHECK, "UNASCHECK"},
963 {IDN_NFCCHECK, "NFCCHECK"},
964 {IDN_PREFCHECK, "PREFCHECK"},
965 {IDN_HYPHCHECK, "HYPHCHECK"},
966 {IDN_COMBCHECK, "COMBCHECK"},
967 {IDN_CTXJCHECK, "CTXJCHECK"},
968 {IDN_CTXOCHECK, "CTXOCHECK"},
969 {IDN_CTXOLITECHECK, "CTXOLITECHECK"},
970 {IDN_BIDICHECK, "BIDICHECK"},
971 {IDN_LOCALCHECK, "LOCALCHECK"},
972 {IDN_IDNCONV, "IDNCONV"},
973 {IDN_LENCHECK, "LENCHECK"},
974 {IDN_RTCHECK, "RTCHECK"},
975 {IDN_LOCALCONV, "LOCALCONV"},
976 {IDN_UNDOIFERR, "UNDOIFERR"},
977 {IDN_LITEFORCEUTF8, "LITEFORCEUTF8"},
978 {0, NULL}
979 };
980
981 void
idn__res_actionstostring(idn_action_t actions,char * string)982 idn__res_actionstostring(idn_action_t actions, char *string) {
983 const struct action_name_table *t;
984 const idn_action_t aux_actions =
985 IDN_LOCALCONV | IDN_LOCALCHECK | IDN_UNDOIFERR;
986
987 *string = '\0';
988 for (t = combined_action_name_table; t->name != NULL; t++) {
989 if ((actions | aux_actions) == (t->action | aux_actions)) {
990 strcpy(string, t->name);
991 actions &= ~t->action;
992 break;
993 }
994 }
995
996 for (t = single_action_name_table; t->name != NULL; t++) {
997 if (actions & t->action) {
998 if (*string != '\0')
999 strcat(string, "|");
1000 strcat(string, t->name);
1001 }
1002 }
1003 }
1004
1005 /*
1006 * Obsolete functions.
1007 */
1008 void
idn_res_enable(int on_off)1009 idn_res_enable(int on_off) {
1010 /* no operation. */
1011 }
1012