libc: make stdio_impl.h an internal libc header
[unleashed/tickless.git] / usr / src / lib / libsip / common / sip_parse_uri.c
blob7a38277fab7fb43c042f0080380984a5ed7e76ee
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "sip_parse_uri.h"
35 * SIP-URI = "sip:" [ userinfo ] hostport uri-parameters [ headers ]
36 * SIPS-URI = "sips:" [ userinfo ] hostport uri-parameters [ headers ]
37 * userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
38 * user = 1*( unreserved / escaped / user-unreserved )
39 * user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
40 * password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
41 * hostport = host [ ":" port ]
42 * host = hostname / IPv4address / IPv6reference
43 * hostname = *( domainlabel "." ) toplabel [ "." ]
44 * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
45 * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
46 * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
47 * IPv6reference = "[" IPv6address "]"
48 * IPv6address = hexpart [ ":" IPv4address ]
49 * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
50 * hexseq = hex4 *( ":" hex4)
51 * hex4 = 1*4HEXDIG
52 * port = 1*DIGIT
54 * The BNF for telephone-subscriber can be found in RFC 2806 [9]. Note,
55 * however, that any characters allowed there that are not allowed in
56 * the user part of the SIP URI MUST be escaped.
58 * uri-parameters = *( ";" uri-parameter)
59 * uri-parameter = transport-param / user-param / method-param
60 * / ttl-param / maddr-param / lr-param / other-param
61 * transport-param = "transport="( "udp" / "tcp" / "sctp" / "tls"
62 * / other-transport)
63 * other-transport = token
64 * user-param = "user=" ( "phone" / "ip" / other-user)
65 * other-user = token
66 * method-param = "method=" Method
67 * ttl-param = "ttl=" ttl
68 * maddr-param = "maddr=" host
69 * lr-param = "lr"
70 * other-param = pname [ "=" pvalue ]
71 * pname = 1*paramchar
72 * pvalue = 1*paramchar
73 * paramchar = param-unreserved / unreserved / escaped
74 * param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
75 * headers = "?" header *( "&" header )
76 * header = hname "=" hvalue
77 * hname = 1*( hnv-unreserved / unreserved / escaped )
78 * hvalue = *( hnv-unreserved / unreserved / escaped )
79 * hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
83 #define SIP_URI_MSG_BUF_SZ 100
85 #define SIP_URI_ISHEX(c) \
86 (((int)(c) >= 0x30 && (int)(c) <= 0x39) || \
87 ((int)(c) >= 0x41 && (int)(c) <= 0x46) || \
88 ((int)(c) >= 0x61 && (int)(c) <= 0x66))
90 #define SIP_URI_ISURLESCAPE(scan, end) \
91 ((scan) + 2 < (end) && (scan)[0] == '%' && \
92 SIP_URI_ISHEX((scan)[1]) && SIP_URI_ISHEX((scan[2])))
95 * URL character classes
96 * mark - _ . ! ~ * ' ()
97 * reserved ; / ? : @ & = + $ , also [] for IPv6
98 * unreserved alphanum mark
99 * pchar : @ & = + $ , unreserved
100 * userinfo ; : & = + $ , unreserved escaped
101 * relsegment ; @ & = + $ , unreserved escaped
102 * reg_name ; : @ & = + $ , unreserved escaped
103 * token - _ . ! ~ * ' % + `
104 * param-unreserved [ ] / : + $ &
105 * hnv-unreserved [ ] / : + $ ?
107 #define SIP_URI_ALPHA_BIT 0x0001
108 #define SIP_URI_DIGIT_BIT 0x0002
109 #define SIP_URI_ALNUM_BITS 0x0003
110 #define SIP_URI_SCHEME_BIT 0x0004 /* for - + . */
111 #define SIP_URI_TOKEN_BIT 0x0008 /* for - _ . ! ~ * ' % + ` */
112 #define SIP_URI_QUEST_BIT 0x0010 /* for ? */
113 #define SIP_URI_AT_BIT 0x0020 /* for @ */
114 #define SIP_URI_COLON_BIT 0x0040 /* for : */
115 #define SIP_URI_SEMI_BIT 0x0080 /* for ; */
116 #define SIP_URI_DASH_BIT 0x0100 /* for - */
117 #define SIP_URI_MARK_BIT 0x0200 /* for - _ . ! ~ * ' ( ) */
118 #define SIP_URI_AND_BIT 0x0400 /* for & */
119 #define SIP_URI_PHCOMM_BIT 0x0800 /* for [ ] / : + $ */
120 #define SIP_URI_OTHER_BIT 0x1000 /* for = + $ , */
121 #define SIP_URI_SLASH_BIT 0x2000 /* for / */
122 #define SIP_URI_VISUALSEP_BIT 0x4000 /* for -.() */
123 #define SIP_URI_DTMFURI_DIGIT_BIT 0x8000 /* for *ABCD */
125 #define a SIP_URI_ALPHA_BIT
126 #define d SIP_URI_DIGIT_BIT
127 #define s SIP_URI_SCHEME_BIT
128 #define t SIP_URI_TOKEN_BIT
129 #define q SIP_URI_QUEST_BIT
130 #define m SIP_URI_AT_BIT
131 #define c SIP_URI_COLON_BIT
132 #define i SIP_URI_SEMI_BIT
133 #define h SIP_URI_DASH_BIT
134 #define k SIP_URI_MARK_BIT
135 #define n SIP_URI_AND_BIT
136 #define o SIP_URI_PHCOMM_BIT
137 #define r SIP_URI_OTHER_BIT
138 #define l SIP_URI_SLASH_BIT
139 #define v SIP_URI_VISUALSEP_BIT
140 #define f SIP_URI_DTMFURI_DIGIT_BIT
142 static const unsigned short sip_uri_table[256] = {
143 0, 0, 0, 0, 0, 0, 0, 0,
144 0, 0, 0, 0, 0, 0, 0, 0,
145 0, 0, 0, 0, 0, 0, 0, 0,
146 0, 0, 0, 0, 0, 0, 0, 0,
147 0, t|k, 0, 0, o|r, t, n, t|k,
148 k|v, k|v, t|k|f, s|t|r|o, r, h|s|t|k|v, s|t|k|v, o|l,
149 d, d, d, d, d, d, d, d,
150 d, d, c|o, i, 0, r, 0, q,
151 m, a|f, a|f, a|f, a|f, a, a, a,
152 a, a, a, a, a, a, a, a,
153 a, a, a, a, a, a, a, a,
154 a, a, a, o, 0, o, 0, t|k,
155 t, a, a, a, a, a, a, a,
156 a, a, a, a, a, a, a, a,
157 a, a, a, a, a, a, a, a,
158 a, a, a, 0, 0, 0, t|k, 0,
159 0, 0, 0, 0, 0, 0, 0, 0,
160 0, 0, 0, 0, 0, 0, 0, 0,
161 0, 0, 0, 0, 0, 0, 0, 0,
162 0, 0, 0, 0, 0, 0, 0, 0,
163 0, 0, 0, 0, 0, 0, 0, 0,
164 0, 0, 0, 0, 0, 0, 0, 0,
165 0, 0, 0, 0, 0, 0, 0, 0,
166 0, 0, 0, 0, 0, 0, 0, 0,
167 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0,
169 0, 0, 0, 0, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0,
174 0, 0, 0, 0, 0, 0, 0, 0,
177 #undef a
178 #undef d
179 #undef s
180 #undef t
181 #undef q
182 #undef m
183 #undef c
184 #undef i
185 #undef h
186 #undef k
187 #undef n
188 #undef o
189 #undef r
190 #undef l
191 #undef v
192 #undef f
194 #define SIP_URI_UT(c) sip_uri_table[(unsigned char)(c)]
195 #define SIP_URI_ISALPHA(c) (SIP_URI_UT(c) & SIP_URI_ALPHA_BIT)
196 #define SIP_URI_ISDIGIT(c) (SIP_URI_UT(c) & SIP_URI_DIGIT_BIT)
197 #define SIP_URI_ISALNUM(c) (SIP_URI_UT(c) & SIP_URI_ALNUM_BITS)
198 #define SIP_URI_ISSCHEME(c) \
199 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_SCHEME_BIT))
200 #define SIP_URI_ISTOKEN(c) \
201 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_TOKEN_BIT))
202 #define SIP_URI_ISSIPDELIM(c) \
203 (SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
204 #define SIP_URI_ISSIPHDELIM(c) \
205 (SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
206 #define SIP_URI_ISHOST(c) \
207 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_DASH_BIT))
208 #define SIP_URI_ISUSER(c) \
209 (SIP_URI_UT(c) & (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT| \
210 SIP_URI_QUEST_BIT|SIP_URI_SLASH_BIT|SIP_URI_AND_BIT))
212 #define SIP_URI_ISABSHDELIM(c) \
213 (SIP_URI_UT(c) & \
214 (SIP_URI_SLASH_BIT|SIP_URI_COLON_BIT|SIP_URI_QUEST_BIT))
215 #define SIP_URI_ISABSDELIM(c) \
216 (SIP_URI_UT(c) & (SIP_URI_SLASH_BIT|SIP_URI_QUEST_BIT))
217 #define SIP_URI_ISUNRESERVED(c) \
218 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
219 #define SIP_URI_ISPARAM(c) \
220 (SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_AND_BIT|\
221 SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
222 #define SIP_URI_ISHEADER(c) \
223 (SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_QUEST_BIT|\
224 SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
225 #define SIP_URI_ISOTHER(c) (SIP_URI_UT(c) & SIP_URI_OTHER_BIT)
226 #define SIP_URI_ISRESERVED(c) \
227 (SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_SLASH_BIT| \
228 SIP_URI_QUEST_BIT| SIP_URI_COLON_BIT|SIP_URI_AT_BIT| \
229 SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
230 #define SIP_URI_ISPCHAR(c) \
231 (SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_AT_BIT| \
232 SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
233 #define SIP_URI_ISREGNAME(c) \
234 (SIP_URI_UT(c) & \
235 (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|SIP_URI_COLON_BIT| \
236 SIP_URI_AT_BIT|SIP_URI_AND_BIT))
237 #define SIP_URI_ISPHONEDIGIT(c) \
238 (SIP_URI_UT(c) & (SIP_URI_DIGIT_BIT|SIP_URI_VISUALSEP_BIT))
239 #define SIP_URI_ISDTMFDIGIT(c) (SIP_URI_UT(c) & SIP_URI_DTMFURI_DIGIT_BIT)
241 static int sip_uri_url_casecmp(const char *, const char *, unsigned);
242 static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
243 static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
244 static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
245 static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
246 static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
247 static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
248 static int sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
249 static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
250 static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
251 static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
252 static void sip_uri_parse_netpath(_sip_uri_t *, char **, char *, boolean_t);
253 static int sip_uri_parse_ipv6(char *, char *);
254 static int sip_uri_parse_ipv4(char *, char *);
255 static int sip_uri_parse_hostname(char *, char *);
256 static int sip_uri_parse_tel(char *, char *);
257 static int sip_uri_parse_tel_areaspe(char *, char *);
258 static int sip_uri_parse_tel_servicepro(char *, char *);
259 static int sip_uri_parse_tel_futureext(char *, char *);
260 static int sip_uri_isTokenchar(char **, char *);
261 static int sip_uri_isEscapedPound(char **, char *);
262 static int sip_uri_hexVal(char *, char *);
263 static int SIP_URI_HEXVAL(int);
266 * get the hex value of a char
268 static int
269 SIP_URI_HEXVAL(int c)
271 if (c >= 0x30 && c <= 0x39)
272 return (c - '0');
273 if (c >= 0x41 && c <= 0x46)
274 return (c - 'A' + 10);
275 if (c >= 0x61 && c <= 0x66)
276 return (c - 'a' + 10);
277 return (c);
281 * basic ASCII case-insensitive comparison
283 static int
284 sip_uri_url_casecmp(const char *str1, const char *str2, unsigned len)
286 unsigned j;
288 for (j = 0; j < len && tolower(str1[j]) == tolower(str2[j]) &&
289 str1[j] != '\0'; ++j) {
292 return (j == len ? 0 : tolower(str2[j]) - tolower(str1[j]));
296 * telephone-subscriber = global-phone-number / local-phone-number
297 * Please refer to RFC 2806
299 static int
300 sip_uri_parse_tel(char *scan, char *uend)
302 char *mark = NULL;
303 int ret = 0;
304 int isGlobal = 0;
305 int quote = 0;
307 if (scan == uend)
308 return (0);
309 if (*scan == '+') {
310 ++scan;
311 isGlobal = 1;
313 mark = scan;
314 if (isGlobal) {
315 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
316 ++scan;
317 } else {
318 while (scan < uend &&
319 (SIP_URI_ISPHONEDIGIT(*scan) ||
320 SIP_URI_ISDTMFDIGIT(*scan) ||
321 sip_uri_isEscapedPound(&scan, uend) ||
322 *scan == 'p' || *scan == 'w')) {
323 ++scan;
326 if (mark == scan || (scan < uend && *scan != ';'))
327 return (0);
330 * parse isdn-subaddress
332 if (uend - scan > 6 && !sip_uri_url_casecmp(scan, ";isub=", 6)) {
333 scan += 6;
334 mark = scan;
335 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
336 ++scan;
337 if (mark == scan || (scan < uend && *scan != ';'))
338 return (0);
342 * parse post-dial
344 if (uend - scan > 7 && !sip_uri_url_casecmp(scan, ";postd=", 7)) {
345 scan += 7;
346 mark = scan;
347 while (scan < uend &&
348 (SIP_URI_ISPHONEDIGIT(*scan) ||
349 SIP_URI_ISDTMFDIGIT(*scan) ||
350 sip_uri_isEscapedPound(&scan, uend) ||
351 *scan == 'p' || *scan == 'w')) {
352 ++scan;
354 if (mark == scan || (scan < uend && *scan != ';'))
355 return (0);
358 if (!isGlobal) {
360 * parse area-specifier
362 if (uend - scan > 15 &&
363 !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
364 scan += 15;
365 mark = scan;
366 while (scan < uend && *scan != ';')
367 ++scan;
368 ret = sip_uri_parse_tel_areaspe(mark, scan);
370 } else {
371 ret = 1;
375 * parse area-specifier, service-provider, future-extension
377 while (scan < uend && ret) {
378 if (uend - scan > 15 &&
379 !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
380 scan += 15;
381 mark = scan;
382 while (scan < uend && *scan != ';')
383 ++scan;
384 ret = sip_uri_parse_tel_areaspe(mark, scan);
385 } else if (uend - scan > 5 &&
386 !sip_uri_url_casecmp(scan, ";tsp=", 5)) {
387 scan += 5;
388 mark = scan;
389 while (scan < uend && *scan != ';')
390 ++scan;
391 ret = sip_uri_parse_tel_servicepro(mark, scan);
392 } else {
393 ++scan;
394 mark = scan;
395 while (scan < uend && (*scan != ';' || quote)) {
396 if (sip_uri_hexVal(scan, uend) == 0x22) {
397 quote = !quote;
398 scan += 3;
399 } else {
400 ++scan;
403 ret = sip_uri_parse_tel_futureext(mark, scan);
406 return (ret && scan == uend);
410 * area-specifier = ";" phone-context-tag "=" phone-context-ident
411 * phone-context-tag = "phone-context"
412 * phone-context-ident = network-prefix / private-prefix
413 * network-prefix = global-network-prefix / local-network-prefix
414 * global-network-prefix = "+" 1*phonedigit
415 * local-network-prefix = 1*(phonedigit / dtmf-digit / pause-character)
416 * private-prefix = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
417 * %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
418 * %x65-6F / %x71-76 / %x78-7E)
419 * *(%x21-3A / %x3C-7E)
420 * phonedigit = DIGIT / visual-separator
421 * visual-separator = "-" / "." / "(" / ")"
422 * pause-character = one-second-pause / wait-for-dial-tone
423 * one-second-pause = "p"
424 * wait-for-dial-tone = "w"
425 * dtmf-digit = "*" / "#" / "A" / "B" / "C" / "D"
427 static int
428 sip_uri_parse_tel_areaspe(char *scan, char *uend)
430 int uri_hexValue;
432 if (scan == uend)
433 return (0);
436 * parse global-network-prefix
438 if (*scan == '+') {
439 ++scan;
440 if (scan == uend)
441 return (0);
442 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
443 ++scan;
445 * parse local-network-prefix
447 } else if (SIP_URI_ISPHONEDIGIT(*scan) || SIP_URI_ISDTMFDIGIT(*scan) ||
448 sip_uri_isEscapedPound(&scan, uend) ||
449 *scan == 'p' || *scan == 'w') {
450 ++scan;
451 while (scan < uend &&
452 (SIP_URI_ISPHONEDIGIT(*scan) ||
453 SIP_URI_ISDTMFDIGIT(*scan) ||
454 sip_uri_isEscapedPound(&scan, uend) ||
455 *scan == 'p' || *scan == 'w')) {
456 ++scan;
458 } else {
460 * parse private-prefix
462 * any characters allowed in RFC 2806 that are not allowed in
463 * the user part of the SIP URI MUST be escaped
465 * private-prefix = (! $ & ', / = ? _
466 * EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
467 * { } | ~ [ ] \ ^ ` " % : < > @)
468 * *(%x21-3A / %x3C-7E)
470 * following characters are allowed in RFC 2806 and
471 * the user part of SIP URI
472 * ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
474 if (*scan == '!' || *scan == '$' || *scan == '&' ||
475 *scan == '\'' || *scan == ',' || *scan == '/' ||
476 *scan == '=' || *scan == '?' || *scan == '_' ||
477 (*scan >= 'E' && *scan <= 'Z' &&
478 *scan != 'P' && *scan != 'W') ||
479 (*scan >= 'e' && *scan <= 'z' &&
480 *scan != 'p' && *scan != 'w')) {
481 ++scan;
482 } else {
483 uri_hexValue = sip_uri_hexVal(scan, uend);
484 if (uri_hexValue == 0x21 || uri_hexValue == 0x22 ||
485 (uri_hexValue >= 0x24 && uri_hexValue <= 0x27) ||
486 uri_hexValue == 0x2c || uri_hexValue == 0x2f ||
487 uri_hexValue == 0x3a ||
488 (uri_hexValue >= 0x3c && uri_hexValue <= 0x40) ||
489 (uri_hexValue >= 0x45 && uri_hexValue <= 0x4f) ||
490 (uri_hexValue >= 0x51 && uri_hexValue <= 0x56) ||
491 (uri_hexValue >= 0x58 && uri_hexValue <= 0x60) ||
492 (uri_hexValue >= 0x65 && uri_hexValue <= 0x6f) ||
493 (uri_hexValue >= 0x71 && uri_hexValue <= 0x76) ||
494 (uri_hexValue >= 0x78 && uri_hexValue <= 0x7e)) {
495 scan += 3;
496 } else {
497 return (0);
501 * parse *(%x21-3A / %x3C-7E)
503 while (scan < uend) {
504 if (SIP_URI_ISUNRESERVED(*scan) ||
505 (SIP_URI_ISUSER(*scan) && *scan != ';')) {
506 ++scan;
507 } else {
508 uri_hexValue = sip_uri_hexVal(scan, uend);
509 if (uri_hexValue >= 0x21 &&
510 uri_hexValue <= 0x7e &&
511 uri_hexValue != 0x3b) {
512 scan += 3;
513 } else {
514 return (0);
519 if (scan < uend)
520 return (0);
521 return (1);
524 static int
525 sip_uri_hexVal(char *scan, char *uend)
527 int ret = -1;
529 if (SIP_URI_ISURLESCAPE(scan, uend)) {
530 ret = (SIP_URI_ISDIGIT(scan[1]) ? (scan[1] - '0') :
531 (tolower(scan[1]) - 'a' + 10)) * 16 +
532 (SIP_URI_ISDIGIT(scan[2]) ? (scan[2] - '0') :
533 (tolower(scan[2]) - 'a' + 10));
535 return (ret);
539 * service-provider = ";" provider-tag "=" provider-hostname
540 * provider-tag = "tsp"
541 * provider-hostname = domain
543 static int
544 sip_uri_parse_tel_servicepro(char *scan, char *uend)
546 char *mark = NULL;
548 if (scan == uend)
549 return (0);
552 * parse domain=" "
554 if (sip_uri_hexVal(scan, uend) == 0x20 && scan + 3 == uend)
555 return (1);
556 while (scan < uend) {
557 mark = scan;
558 while (scan < uend && (*scan == '-'|| SIP_URI_ISALNUM(*scan)))
559 ++scan;
560 if ((scan < uend && *scan != '.') ||
561 !SIP_URI_ISALPHA(*mark) || !SIP_URI_ISALNUM(*(scan - 1))) {
562 return (0);
564 if (scan < uend)
565 ++scan;
568 if (scan < uend)
569 return (0);
570 return (1);
574 * future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
575 * ["?" 1*(token-char)]) / quoted-string )]
576 * token-char = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
577 * / %x41-5A / %x5E-7A / %x7C / %x7E)
579 static int
580 sip_uri_parse_tel_futureext(char *scan, char *uend)
582 char *mark;
583 int uri_hexValue = 0;
585 if (scan == uend)
586 return (0);
589 * parse 1*(token-char)
591 mark = scan;
592 while (scan < uend && sip_uri_isTokenchar(&scan, uend))
594 if (mark == scan ||
595 (scan < uend && (*scan != '=' || scan + 1 == uend))) {
596 return (0);
598 if (scan == uend)
599 return (1);
600 ++scan;
603 * parse 1*token-char ["?" 1*token-char]
605 if (sip_uri_isTokenchar(&scan, uend)) {
606 while (sip_uri_isTokenchar(&scan, uend))
608 if (scan < uend) {
609 if (*scan != '?')
610 return (0);
611 ++scan;
612 mark = scan;
613 while (sip_uri_isTokenchar(&scan, uend))
615 if (mark == scan)
616 return (0);
618 } else { /* parse quoted-string */
619 uri_hexValue = sip_uri_hexVal(scan, uend);
620 if (uri_hexValue != 0x22)
621 return (0);
622 scan += 3;
623 while (scan < uend && sip_uri_hexVal(scan, uend) != 0x22) {
625 * parse "\" CHAR
627 if (sip_uri_hexVal(scan, uend) == 0x5c) {
628 scan += 3;
629 if (scan < uend) {
630 if (SIP_URI_ISUNRESERVED(*scan) ||
631 SIP_URI_ISUSER(*scan)) {
632 ++scan;
633 } else if (sip_uri_hexVal(scan, uend) >=
634 0x00 &&
635 sip_uri_hexVal(scan, uend) <=
636 0x7f) {
637 scan += 3;
638 } else {
639 return (0);
641 } else {
642 return (0);
644 } else {
645 if (SIP_URI_ISUNRESERVED(*scan) ||
646 SIP_URI_ISUSER(*scan)) {
647 ++scan;
648 } else {
649 uri_hexValue =
650 sip_uri_hexVal(scan, uend);
651 if ((uri_hexValue >= 0x20 &&
652 uri_hexValue <= 0x21) ||
653 (uri_hexValue >= 0x23 &&
654 uri_hexValue <= 0x7e) ||
655 (uri_hexValue >= 0x80 &&
656 uri_hexValue <= 0xff)) {
657 scan += 3;
658 } else {
659 return (0);
664 if (scan == uend ||
665 (scan < uend && sip_uri_hexVal(scan, uend) != 0x22)) {
666 return (0);
668 scan += 3;
671 if (scan < uend)
672 return (0);
673 return (1);
677 * Any characters allowed in RFC2806 tel URL that are not allowed in
678 * the user part of the SIP URI MUST be escaped.
679 * token-char = - _ . ! ~ * ' $ & + DIGIT ALPHA # % ^ ` |
681 static int
682 sip_uri_isTokenchar(char **pscan, char *uend)
684 char *scan = *pscan;
685 int uri_hexValue = 0;
687 if (scan == uend)
688 return (0);
691 * for ALPAH DIGIT - _ . ! ~ * ' $ & +
693 if ((SIP_URI_ISUNRESERVED(*scan) && *scan != '(' && *scan != ')') ||
694 *scan == '$' || *scan == '&' || *scan == '+') {
695 ++scan;
696 *pscan = scan;
697 return (1);
700 uri_hexValue = sip_uri_hexVal(scan, uend);
701 if (uri_hexValue == 0x21 || uri_hexValue == 0x7c ||
702 uri_hexValue == 0x7e ||
703 (uri_hexValue >= 0x23 && uri_hexValue <= 0x27) ||
704 (uri_hexValue >= 0x2a && uri_hexValue <= 0x2b) ||
705 (uri_hexValue >= 0x2d && uri_hexValue <= 0x2e) ||
706 (uri_hexValue >= 0x30 && uri_hexValue <= 0x39) ||
707 (uri_hexValue >= 0x41 && uri_hexValue <= 0x5a) ||
708 (uri_hexValue >= 0x5e && uri_hexValue <= 0x7a)) {
709 scan += 3;
710 *pscan = scan;
711 return (1);
713 return (0);
717 * '#' is not allowed in the telephone-subscriber part of SIP URI
718 * it must be escaped
720 static int
721 sip_uri_isEscapedPound(char **pscan, char *uend)
723 char *scan = *pscan;
725 if (scan == uend)
726 return (0);
727 if (*scan == '%' && scan + 2 < uend && scan[1] == '2' &&
728 scan[2] == '3') {
729 scan += 2;
730 *pscan = scan;
731 return (1);
733 return (0);
737 * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
739 static int
740 sip_uri_parse_scheme(_sip_uri_t *outurl, char *scan, char *uend)
742 if (scan == uend) {
743 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
744 return (0);
746 outurl->sip_uri_scheme.sip_str_ptr = scan;
747 outurl->sip_uri_scheme.sip_str_len = uend - scan;
749 if (scan < uend && SIP_URI_ISALPHA(*scan)) {
750 ++scan;
751 while (scan < uend && SIP_URI_ISSCHEME(*scan))
752 ++scan;
754 if (scan < uend)
755 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
756 return (1);
760 * The format of params is supposed to be;XXX;XXX;XXX
761 * uri-parameters = *(";" uri-parameter)
762 * uri-parameter = transport-param / user-param / method-param
763 * / ttl-param / maddr-param / lr-param / other-param
764 * transport-param = "transport="
765 * ("udp" / "tcp" / "sctp" / "tls" / other-transport)
766 * other-transport = token
767 * user-param = "user=" ("phone" / "ip" / other-user)
768 * other-user = token
769 * method-param = "method=" Method
770 * ttl-param = "ttl=" ttl
771 * maddr-param = "maddr=" host
772 * lr-param = "lr"
773 * other-param = pname [ "=" pvalue ]
774 * pname = 1*paramchar
775 * pvalue = 1*paramchar
776 * paramchar = param-unreserved / unreserved / escaped
777 * param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
779 static void
780 sip_uri_parse_params(_sip_uri_t *outurl, char *scan, char *uend)
782 char *mark = NULL;
783 char *equal = NULL;
784 int i = 0;
785 int ttl = 0;
786 int paramleftlen = 0;
787 int gothost = 0;
788 sip_param_t *param = NULL;
789 sip_param_t *new_param = NULL;
791 if (scan == uend || *scan != ';' || scan + 1 == uend) {
792 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
793 return;
796 while (scan < uend) {
797 mark = ++scan;
798 while (scan < uend && *scan != ';')
799 ++scan;
800 if (scan == mark) {
801 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
802 return;
805 new_param = calloc(1, sizeof (sip_param_t));
806 if (new_param == NULL) {
807 outurl->sip_uri_errflags |= SIP_URIERR_MEMORY;
808 return;
811 if (param == NULL)
812 outurl->sip_uri_params = new_param;
813 else
814 param->param_next = new_param;
816 param = new_param;
818 param->param_name.sip_str_ptr = mark;
819 equal = memchr(mark, '=', scan - mark);
820 if (equal == NULL) {
821 param->param_name.sip_str_len = scan - mark;
822 param->param_value.sip_str_ptr = NULL;
823 param->param_value.sip_str_len = 0;
824 while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
825 SIP_URI_ISURLESCAPE(mark, scan))) {
826 ++mark;
828 } else {
829 param->param_name.sip_str_len = equal - mark;
830 param->param_value.sip_str_ptr = equal + 1;
831 param->param_value.sip_str_len = scan - equal - 1;
833 if (mark == equal || equal + 1 == scan) {
834 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
835 return;
837 paramleftlen = equal - mark + 1;
838 if ((paramleftlen == 10 &&
839 !sip_uri_url_casecmp(mark, "transport=", 10)) ||
840 (paramleftlen == 5 &&
841 !sip_uri_url_casecmp(mark, "user=", 5)) ||
842 (paramleftlen == 7 &&
843 !sip_uri_url_casecmp(mark, "method=", 7))) {
844 if (scan - equal == 1) {
845 outurl->sip_uri_errflags |=
846 SIP_URIERR_PARAM;
847 return;
849 mark = equal + 1;
850 while (mark < scan && SIP_URI_ISTOKEN(*mark))
851 ++mark;
852 } else if (paramleftlen == 4 &&
853 !sip_uri_url_casecmp(mark, "ttl=", 4)) {
854 if (scan - equal == 1) {
855 outurl->sip_uri_errflags |=
856 SIP_URIERR_PARAM;
857 return;
859 mark = equal;
860 for (i = 0; i < 3; ++i) {
861 ++mark;
862 if (mark < scan &&
863 SIP_URI_ISDIGIT(*mark)) {
864 ttl = ttl * 10 + (*mark - '0');
866 if (ttl > 255) {
867 outurl->sip_uri_errflags |=
868 SIP_URIERR_PARAM;
869 return;
872 } else if (paramleftlen == 6 &&
873 !sip_uri_url_casecmp(mark, "maddr=", 6)) {
874 gothost = 0;
875 mark = equal + 1;
876 if (mark < scan && SIP_URI_ISDIGIT(*mark)) {
877 gothost = sip_uri_parse_ipv4(mark,
878 scan);
881 * not valid syntax for a host or user name,
882 * try IPv6 literal
884 if (!gothost && mark < scan && *mark == '[') {
885 gothost = sip_uri_parse_ipv6(mark,
886 scan);
889 * look for a valid host name:
890 * *(domainlabel ".") toplabel ["."]
892 if (!gothost && mark < scan) {
893 if (!(gothost =
894 sip_uri_parse_hostname(mark,
895 scan))) {
896 outurl->sip_uri_errflags |=
897 SIP_URIERR_PARAM;
900 if (gothost)
901 mark = scan;
902 } else if (paramleftlen == 3 &&
903 !sip_uri_url_casecmp(mark, "lr=", 3)) {
904 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
905 return;
906 } else {
907 while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
908 SIP_URI_ISURLESCAPE(mark, scan) ||
909 mark == equal)) {
910 ++mark;
914 if (mark < scan) {
915 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
916 return;
922 * The format of headers is supposed to be ?XXX&XXX&XXX
923 * headers = "?" header *("&" header
924 * header = hname "=" hvalue
925 * hname = 1*(hnv-unreserved / unreserved / escaped
926 * hvalue = *(hnv-unreserved / unreserved / escaped
927 * hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
929 static void
930 sip_uri_parse_headers(_sip_uri_t *outurl, char *scan, char *uend)
932 char *mark = NULL;
933 char *equal = NULL;
935 if (scan == uend || *scan != '?' || scan + 1 == uend) {
936 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
937 return;
939 outurl->sip_uri_headers.sip_str_ptr = scan + 1;
940 outurl->sip_uri_headers.sip_str_len = uend - (scan + 1);
942 while (scan < uend) {
943 mark = ++scan;
944 while (scan < uend && *scan != '&')
945 ++scan;
946 if (scan == mark) {
947 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
948 return;
950 equal = memchr(mark, '=', scan - mark);
951 if (equal == mark || equal == NULL) {
952 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
953 return;
955 while (mark < scan &&
956 (SIP_URI_ISHEADER(*mark) ||
957 SIP_URI_ISURLESCAPE(mark, scan) || mark == equal)) {
958 ++mark;
960 if (mark < scan) {
961 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
962 return;
968 * opaque-part = uric-no-slash *uric
969 * uric = reserved / unreserved / escaped
970 * uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
971 * / "&" / "=" / "+" / "$" / ","
973 static void
974 sip_uri_parse_abs_opaque(_sip_uri_t *outurl, char *scan, char *uend)
976 if (scan == uend) {
977 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
978 return;
980 outurl->sip_uri_opaque.sip_str_ptr = scan;
981 outurl->sip_uri_opaque.sip_str_len = uend - scan;
983 if (SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
984 SIP_URI_ISOTHER(*scan) || *scan == ';' || *scan == '?' ||
985 *scan == ':' || *scan == '@' || *scan == '&') {
986 ++scan;
987 } else {
988 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
989 return;
991 while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
992 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
993 ++scan;
995 if (scan < uend)
996 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
1000 * format of query is supposed to be ?XXX
1001 * query = *uric
1002 * uric = reserved / unreserved / escaped
1004 static void
1005 sip_uri_parse_abs_query(_sip_uri_t *outurl, char *scan, char *uend)
1007 if (uend == scan || *scan != '?' || scan + 1 == uend)
1008 return;
1009 ++scan;
1010 outurl->sip_uri_query.sip_str_ptr = scan;
1011 outurl->sip_uri_query.sip_str_len = uend - scan;
1013 while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
1014 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
1015 ++scan;
1017 if (scan < uend)
1018 outurl->sip_uri_errflags |= SIP_URIERR_QUERY;
1022 * the format of path is supposed to be /XXX;XXX/XXX;
1023 * abs-path = "/" path-segments
1024 * path-segments = segment *( "/" segment )
1025 * segment = *pchar *( ";" param )
1026 * param = *pchar
1027 * pchar = unreserved / escaped /
1028 * ":" / "@" / "&" / "=" / "+" / "$" / ","
1030 static void
1031 sip_uri_parse_abs_path(_sip_uri_t *outurl, char *scan, char *uend)
1033 if (scan == uend || *scan != '/')
1034 return;
1035 outurl->sip_uri_path.sip_str_ptr = scan;
1036 outurl->sip_uri_path.sip_str_len = uend - scan;
1038 ++scan;
1039 while (scan < uend && (SIP_URI_ISPCHAR(*scan) ||
1040 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
1041 *scan == '/' || *scan == ';')) {
1042 ++scan;
1044 if (scan < uend)
1045 outurl->sip_uri_errflags |= SIP_URIERR_PATH;
1048 * reg-name = 1*( unreserved / escaped / "$" / "," / ";"
1049 * / ":" / "@" / "&" / "=" / "+" )
1051 static void
1052 sip_uri_parse_abs_regname(_sip_uri_t *outurl, char *scan, char *uend)
1054 if (scan == uend)
1055 return;
1056 outurl->sip_uri_regname.sip_str_ptr = scan;
1057 outurl->sip_uri_regname.sip_str_len = uend - scan;
1059 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1060 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISREGNAME(*scan))) {
1061 ++scan;
1063 if (scan < uend)
1064 outurl->sip_uri_errflags |= SIP_URIERR_REGNAME;
1068 * The format of the password is supposed to be :XXX
1069 * password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
1071 static void
1072 sip_uri_parse_password(_sip_uri_t *outurl, char *scan, char *uend)
1074 if (scan == uend || *scan != ':' || scan + 1 == uend)
1075 return;
1076 ++scan;
1077 outurl->sip_uri_password.sip_str_ptr = scan;
1078 outurl->sip_uri_password.sip_str_len = uend - scan;
1080 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1081 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISOTHER(*scan) ||
1082 *scan == '&')) {
1083 ++scan;
1085 if (scan < uend)
1086 outurl->sip_uri_errflags |= SIP_URIERR_PASS;
1090 * user = 1*( unreserved / escaped / user-unreserved )
1091 * user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
1093 static void
1094 sip_uri_parse_user(_sip_uri_t *outurl, char *scan, char *uend)
1096 if (scan == uend) {
1097 outurl->sip_uri_errflags |= SIP_URIERR_USER;
1098 return;
1100 outurl->sip_uri_user.sip_str_ptr = scan;
1101 outurl->sip_uri_user.sip_str_len = uend - scan;
1103 if (sip_uri_parse_tel(scan, uend)) {
1104 outurl->sip_uri_isteluser = B_TRUE;
1105 } else {
1106 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1107 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISUSER(*scan))) {
1108 ++scan;
1110 if (scan < uend)
1111 outurl->sip_uri_errflags |= SIP_URIERR_USER;
1116 * the format of port is supposed to be :XXX
1117 * port = 1*DIGIT
1119 static void
1120 sip_uri_parse_port(_sip_uri_t *outurl, char *scan, char *uend)
1122 if (scan == uend || *scan != ':' || scan + 1 == uend) {
1123 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1124 return;
1126 ++scan;
1128 * parse numeric port number
1130 if (SIP_URI_ISDIGIT(*scan)) {
1131 outurl->sip_uri_port = *scan - '0';
1132 while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1133 outurl->sip_uri_port =
1134 outurl->sip_uri_port * 10 + (*scan - '0');
1135 if (outurl->sip_uri_port > 0xffff) {
1136 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1137 outurl->sip_uri_port = 0;
1138 break;
1142 if (scan < uend) {
1143 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1144 outurl->sip_uri_port = 0;
1149 * parse an IPv4 address
1150 * 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1151 * advances pscan to end of IPv4 address, or after last "." that was
1152 * a valid IPv4 or domain name.
1153 * returns 1 if ipv4 found, 0 otherwise
1155 static int
1156 sip_uri_parse_ipv4(char *scan, char *uend)
1158 int j = 0;
1159 int val = 0;
1161 for (j = 0; j < 4; ++j) {
1162 if (!SIP_URI_ISDIGIT(*scan))
1163 break;
1164 val = *scan - '0';
1165 while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1166 val = val * 10 + (*scan - '0');
1167 if (val > 255)
1168 return (0);
1170 if (j < 3) {
1171 if (*scan != '.')
1172 break;
1173 ++scan;
1177 if (j == 4 && scan == uend)
1178 return (1);
1180 return (0);
1184 * parse an IPv6 address
1185 * IPv6address = hexpart [ ":" IPv4address ]
1186 * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1187 * hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
1188 * hexseq = hex4 *( ":" hex4)
1189 * hex4 = 1*4HEXDIG
1190 * if not found, leaves pscan unchanged, otherwise advances to end
1191 * returns 1 if valid,
1192 * 0 if invalid
1194 static int
1195 sip_uri_parse_ipv6(char *scan, char *uend)
1197 char *mark;
1198 unsigned j = 0; /* index for addr */
1199 unsigned val = 0; /* hex value */
1200 int zpad = 0; /* index of :: delimiter */
1202 if (*scan != '[')
1203 return (0);
1204 ++scan;
1205 j = 0;
1208 * check for leading "::", set zpad to the position of the "::"
1210 if (scan + 1 < uend && scan[0] == ':' && scan[1] == ':') {
1211 zpad = 0;
1212 scan += 2;
1213 } else {
1214 zpad = -1;
1218 * loop through up to 16 bytes of IPv6 address
1220 while (scan < uend && j < 15) {
1221 if (!SIP_URI_ISHEX(*scan))
1222 break;
1223 mark = scan;
1224 val = SIP_URI_HEXVAL(*scan);
1225 while (++scan < uend && SIP_URI_ISHEX(*scan)) {
1226 val = val * 16 + SIP_URI_HEXVAL(*scan);
1227 if (val > 0xffff)
1228 return (0);
1232 * always require a delimiter or ]
1234 if (scan == uend)
1235 return (0);
1237 if (*scan == '.' && (j == 12 || (zpad != -1 && j < 12)) &&
1238 mark < uend && sip_uri_parse_ipv4(mark, uend - 1) &&
1239 *(uend - 1) == ']') {
1240 mark = uend - 1;
1241 j += 4;
1242 scan = mark + 1;
1243 break;
1247 * set address
1249 j += 2;
1252 * check for delimiter or ]
1254 if (*scan == ':') {
1256 * found ":" delimiter, check for "::"
1258 if (++scan < uend && *scan == ':') {
1259 if (zpad != -1)
1260 return (0);
1261 zpad = j;
1262 if (++scan < uend && *scan == ']') {
1263 ++scan;
1264 break;
1267 } else if (*scan == ']' && (j == 16 || zpad != -1)) {
1268 ++scan;
1269 break;
1270 } else {
1272 * not a valid delimiter
1274 return (0);
1277 if (zpad == -1 && j < 16)
1278 return (0);
1279 if (zpad != -1) {
1280 if (j > 15)
1281 return (0);
1284 if (scan == uend)
1285 return (1);
1287 return (0);
1291 * hostname = *( domainlabel "." ) toplabel [ "." ]
1292 * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
1293 * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
1295 static int
1296 sip_uri_parse_hostname(char *scan, char *uend)
1298 int sawalpha = 0;
1300 if (scan < uend && SIP_URI_ISALNUM(*scan)) {
1301 do {
1302 sawalpha = SIP_URI_ISALPHA(*scan);
1303 while (SIP_URI_ISHOST(*scan))
1304 ++scan;
1305 if (*scan != '.')
1306 break;
1307 ++scan;
1308 } while (scan < uend && SIP_URI_ISALNUM(*scan));
1311 if (sawalpha && scan == uend)
1312 return (1);
1313 return (0);
1318 * parse the network path portion of a full URL
1320 static void
1321 sip_uri_parse_netpath(_sip_uri_t *outurl, char **pscan, char *uend,
1322 boolean_t issip)
1324 char *mark = NULL;
1325 char *mark2 = NULL;
1326 char *scan = *pscan;
1327 int gothost = 0;
1330 * look for the first high-level delimiter
1332 mark = scan;
1333 while (scan < uend && *scan != '@')
1334 ++scan;
1336 * handle userinfo section of URL
1338 if (scan < uend && *scan == '@') {
1340 * parse user
1342 mark2 = mark;
1343 while (mark < scan && *mark != ':')
1344 ++mark;
1345 sip_uri_parse_user(outurl, mark2, mark);
1347 * parse password
1349 if (*mark == ':')
1350 sip_uri_parse_password(outurl, mark, scan);
1351 mark = ++scan;
1354 scan = mark;
1355 if (scan < uend && *scan == '[') { /* look for an IPv6 address */
1356 while (scan < uend && *scan != ']')
1357 ++scan;
1358 if (scan < uend) {
1359 ++scan;
1360 if (sip_uri_parse_ipv6(mark, scan))
1361 gothost = 1;
1363 } else {
1364 while (scan < uend && ((issip && !SIP_URI_ISSIPHDELIM(*scan)) ||
1365 (!issip && !SIP_URI_ISABSHDELIM(*scan)))) {
1366 ++scan;
1370 * look for an IPv4 address
1372 if (mark < scan && SIP_URI_ISDIGIT(*mark) &&
1373 sip_uri_parse_ipv4(mark, scan)) {
1374 gothost = 1;
1378 * look for a valid host name
1380 if (!gothost && mark < scan &&
1381 sip_uri_parse_hostname(mark, scan)) {
1382 gothost = 1;
1386 * handle invalid host name
1388 if (!gothost)
1389 outurl->sip_uri_errflags |= SIP_URIERR_HOST;
1391 * save host name
1393 outurl->sip_uri_host.sip_str_ptr = mark;
1394 outurl->sip_uri_host.sip_str_len = scan - mark;
1396 mark = scan;
1398 * parse the port number
1400 if (scan < uend && *scan == ':') {
1401 while (scan < uend && ((issip && !SIP_URI_ISSIPDELIM(*scan)) ||
1402 (!issip && !SIP_URI_ISABSDELIM(*scan)))) {
1403 ++scan;
1405 sip_uri_parse_port(outurl, mark, scan);
1409 * set return pointer
1411 *pscan = scan;
1415 * parse a URL
1416 * URL = SIP-URI / SIPS-URI / absoluteURI
1418 void
1419 sip_uri_parse_it(_sip_uri_t *outurl, sip_str_t *uri_str)
1421 char *mark;
1422 char *scan;
1423 char *uend;
1424 char *str = uri_str->sip_str_ptr;
1425 unsigned urlen = uri_str->sip_str_len;
1428 * reset output parameters
1430 (void) memset(outurl, 0, sizeof (sip_uri_t));
1433 * strip enclosing angle brackets
1435 if (urlen > 1 && str[0] == '<' && str[urlen-1] == '>') {
1436 urlen -= 2;
1437 ++str;
1439 uend = str + urlen;
1442 * strip off space prefix and trailing spaces
1444 while (str < uend && isspace(*str)) {
1445 ++str;
1446 --urlen;
1448 while (str < uend && isspace(*(uend - 1))) {
1449 --uend;
1450 --urlen;
1454 * strip off "URL:" prefix
1456 if (urlen > 4 && sip_uri_url_casecmp(str, "URL:", 4) == 0) {
1457 str += 4;
1458 urlen -= 4;
1462 * parse the scheme name
1464 mark = scan = str;
1465 while (scan < uend && *scan != ':')
1466 ++scan;
1467 if (scan == uend || !sip_uri_parse_scheme(outurl, mark, scan)) {
1468 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
1469 return;
1472 if ((outurl->sip_uri_scheme.sip_str_len == SIP_SCHEME_LEN &&
1473 !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIP_SCHEME,
1474 SIP_SCHEME_LEN)) ||
1475 (outurl->sip_uri_scheme.sip_str_len == SIPS_SCHEME_LEN &&
1476 !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIPS_SCHEME,
1477 SIPS_SCHEME_LEN))) {
1478 outurl->sip_uri_issip = B_TRUE;
1479 } else {
1480 outurl->sip_uri_issip = B_FALSE;
1482 ++scan; /* skip ':' */
1484 if (outurl->sip_uri_issip) {
1486 * parse SIP URL
1488 sip_uri_parse_netpath(outurl, &scan, uend, B_TRUE);
1491 * parse parameters
1493 if (scan < uend && *scan == ';') {
1494 mark = scan;
1495 while (scan < uend && *scan != '?')
1496 ++scan;
1497 sip_uri_parse_params(outurl, mark, scan);
1501 * parse headers
1503 if (scan < uend && *scan == '?')
1504 sip_uri_parse_headers(outurl, scan, uend);
1505 } else if (scan < uend && scan[0] == '/') { /* parse absoluteURL */
1506 ++scan;
1508 * parse authority
1509 * authority = srvr / reg-name
1510 * srvr = [ [ userinfo "@" ] hostport ]
1511 * reg-name = 1*(unreserved / escaped / "$" / ","
1512 * / ";" / ":" / "@" / "&" / "=" / "+")
1514 if (scan < uend && *scan == '/') {
1515 ++scan;
1516 mark = scan;
1518 * take authority as srvr
1520 sip_uri_parse_netpath(outurl, &scan, uend, B_FALSE);
1523 * if srvr failed, take it as reg-name
1524 * parse reg-name
1526 if (outurl->sip_uri_errflags & SIP_URIERR_USER ||
1527 outurl->sip_uri_errflags & SIP_URIERR_PASS ||
1528 outurl->sip_uri_errflags & SIP_URIERR_HOST ||
1529 outurl->sip_uri_errflags & SIP_URIERR_PORT) {
1530 scan = mark;
1531 while (scan < uend && *scan != '/' &&
1532 *scan != '?') {
1533 ++scan;
1535 sip_uri_parse_abs_regname(outurl, mark, scan);
1536 if (!(outurl->sip_uri_errflags &
1537 SIP_URIERR_REGNAME)) {
1539 * remove error info of user,
1540 * password, host, port
1542 outurl->sip_uri_user.sip_str_ptr = NULL;
1543 outurl->sip_uri_user.sip_str_len = 0;
1544 outurl->sip_uri_errflags &=
1545 ~SIP_URIERR_USER;
1546 outurl->sip_uri_password.sip_str_ptr =
1547 NULL;
1548 outurl->sip_uri_password.sip_str_len =
1550 outurl->sip_uri_errflags &=
1551 ~SIP_URIERR_PASS;
1552 outurl->sip_uri_host.sip_str_ptr = NULL;
1553 outurl->sip_uri_host.sip_str_len = 0;
1554 outurl->sip_uri_errflags &=
1555 ~SIP_URIERR_HOST;
1556 outurl->sip_uri_port = 0;
1557 outurl->sip_uri_errflags &=
1558 ~SIP_URIERR_PORT;
1561 } else {
1563 * there is no net-path
1565 --scan;
1568 * parse abs-path
1570 if (scan < uend && *scan == '/') {
1571 mark = scan;
1572 while (scan < uend && *scan != '?')
1573 ++scan;
1574 sip_uri_parse_abs_path(outurl, mark, scan);
1578 * parse query
1580 if (scan < uend && *scan == '?')
1581 sip_uri_parse_abs_query(outurl, scan, uend);
1582 } else {
1584 * parse opaque-part
1586 sip_uri_parse_abs_opaque(outurl, scan, uend);