1*2882Svi117747 /*
2*2882Svi117747  * CDDL HEADER START
3*2882Svi117747  *
4*2882Svi117747  * The contents of this file are subject to the terms of the
5*2882Svi117747  * Common Development and Distribution License (the "License").
6*2882Svi117747  * You may not use this file except in compliance with the License.
7*2882Svi117747  *
8*2882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2882Svi117747  * or http://www.opensolaris.org/os/licensing.
10*2882Svi117747  * See the License for the specific language governing permissions
11*2882Svi117747  * and limitations under the License.
12*2882Svi117747  *
13*2882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
14*2882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
16*2882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
17*2882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2882Svi117747  *
19*2882Svi117747  * CDDL HEADER END
20*2882Svi117747  */
21*2882Svi117747 
22*2882Svi117747 /*
23*2882Svi117747  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2882Svi117747  * Use is subject to license terms.
25*2882Svi117747  */
26*2882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*2882Svi117747 
28*2882Svi117747 #include <stdlib.h>
29*2882Svi117747 #include <string.h>
30*2882Svi117747 #include <ctype.h>
31*2882Svi117747 
32*2882Svi117747 #include "sip_parse_uri.h"
33*2882Svi117747 
34*2882Svi117747 /*
35*2882Svi117747  * SIP-URI          =  "sip:" [ userinfo ] hostport uri-parameters [ headers ]
36*2882Svi117747  * SIPS-URI         =  "sips:" [ userinfo ] hostport uri-parameters [ headers ]
37*2882Svi117747  * userinfo         =  ( user / telephone-subscriber ) [ ":" password ] "@"
38*2882Svi117747  * user             =  1*( unreserved / escaped / user-unreserved )
39*2882Svi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
40*2882Svi117747  * password         =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
41*2882Svi117747  * hostport         =  host [ ":" port ]
42*2882Svi117747  * host             =  hostname / IPv4address / IPv6reference
43*2882Svi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
44*2882Svi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
45*2882Svi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
46*2882Svi117747  * IPv4address    =  1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
47*2882Svi117747  * IPv6reference  =  "[" IPv6address "]"
48*2882Svi117747  * IPv6address    =  hexpart [ ":" IPv4address ]
49*2882Svi117747  * hexpart        =  hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
50*2882Svi117747  * hexseq         =  hex4 *( ":" hex4)
51*2882Svi117747  * hex4           =  1*4HEXDIG
52*2882Svi117747  * port           =  1*DIGIT
53*2882Svi117747  *
54*2882Svi117747  * The BNF for telephone-subscriber can be found in RFC 2806 [9].  Note,
55*2882Svi117747  * however, that any characters allowed there that are not allowed in
56*2882Svi117747  * the user part of the SIP URI MUST be escaped.
57*2882Svi117747  *
58*2882Svi117747  * uri-parameters    =  *( ";" uri-parameter)
59*2882Svi117747  * uri-parameter     =  transport-param / user-param / method-param
60*2882Svi117747  *                      / ttl-param / maddr-param / lr-param / other-param
61*2882Svi117747  * transport-param   =  "transport="( "udp" / "tcp" / "sctp" / "tls"
62*2882Svi117747  *                     / other-transport)
63*2882Svi117747  * other-transport   =  token
64*2882Svi117747  * user-param        =  "user=" ( "phone" / "ip" / other-user)
65*2882Svi117747  * other-user        =  token
66*2882Svi117747  * method-param      =  "method=" Method
67*2882Svi117747  * ttl-param         =  "ttl=" ttl
68*2882Svi117747  * maddr-param       =  "maddr=" host
69*2882Svi117747  * lr-param          =  "lr"
70*2882Svi117747  * other-param       =  pname [ "=" pvalue ]
71*2882Svi117747  * pname             =  1*paramchar
72*2882Svi117747  * pvalue            =  1*paramchar
73*2882Svi117747  * paramchar         =  param-unreserved / unreserved / escaped
74*2882Svi117747  * param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
75*2882Svi117747  * headers         =  "?" header *( "&" header )
76*2882Svi117747  * header          =  hname "=" hvalue
77*2882Svi117747  * hname           =  1*( hnv-unreserved / unreserved / escaped )
78*2882Svi117747  * hvalue          =  *( hnv-unreserved / unreserved / escaped )
79*2882Svi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
80*2882Svi117747  *
81*2882Svi117747  */
82*2882Svi117747 
83*2882Svi117747 #define	SIP_URI_MSG_BUF_SZ	100
84*2882Svi117747 
85*2882Svi117747 #define	SIP_URI_ISHEX(c)					\
86*2882Svi117747 	(((int)(c) >= 0x30 && (int)(c) <= 0x39) || 	\
87*2882Svi117747 	((int)(c) >= 0x41 && (int)(c) <= 0x46) || 	\
88*2882Svi117747 	((int)(c) >= 0x61 && (int)(c) <= 0x66))
89*2882Svi117747 
90*2882Svi117747 #define	SIP_URI_ISURLESCAPE(scan, end)			\
91*2882Svi117747 	((scan) + 2 < (end) && (scan)[0] == '%' && 	\
92*2882Svi117747 	SIP_URI_ISHEX((scan)[1]) && SIP_URI_ISHEX((scan[2])))
93*2882Svi117747 
94*2882Svi117747 /*
95*2882Svi117747  * URL character classes
96*2882Svi117747  *  mark	- _ . ! ~ * ' ()
97*2882Svi117747  *  reserved	; / ? : @ & = + $ ,    also [] for IPv6
98*2882Svi117747  *  unreserved	alphanum mark
99*2882Svi117747  *  pchar	: @ & = + $ , unreserved
100*2882Svi117747  *  userinfo	; : & = + $ , unreserved escaped
101*2882Svi117747  *  relsegment	; @ & = + $ , unreserved escaped
102*2882Svi117747  *  reg_name	; : @ & = + $ , unreserved escaped
103*2882Svi117747  *  token	- _ . ! ~ * ' %  + `
104*2882Svi117747  *  param-unreserved  [ ] / : + $ &
105*2882Svi117747  *  hnv-unreserved    [ ] / : + $ ?
106*2882Svi117747  */
107*2882Svi117747 #define	SIP_URI_ALPHA_BIT		0x0001
108*2882Svi117747 #define	SIP_URI_DIGIT_BIT		0x0002
109*2882Svi117747 #define	SIP_URI_ALNUM_BITS		0x0003
110*2882Svi117747 #define	SIP_URI_SCHEME_BIT		0x0004	/* for - + . */
111*2882Svi117747 #define	SIP_URI_TOKEN_BIT		0x0008	/* for - _ . ! ~ * ' % + ` */
112*2882Svi117747 #define	SIP_URI_QUEST_BIT		0x0010	/* for ? */
113*2882Svi117747 #define	SIP_URI_AT_BIT			0x0020	/* for @ */
114*2882Svi117747 #define	SIP_URI_COLON_BIT		0x0040	/* for : */
115*2882Svi117747 #define	SIP_URI_SEMI_BIT		0x0080	/* for ; */
116*2882Svi117747 #define	SIP_URI_DASH_BIT		0x0100	/* for - */
117*2882Svi117747 #define	SIP_URI_MARK_BIT		0x0200	/* for - _ . ! ~ * ' ( ) */
118*2882Svi117747 #define	SIP_URI_AND_BIT			0x0400	/* for & */
119*2882Svi117747 #define	SIP_URI_PHCOMM_BIT		0x0800	/* for [ ] / : + $ */
120*2882Svi117747 #define	SIP_URI_OTHER_BIT		0x1000	/* for = + $ , */
121*2882Svi117747 #define	SIP_URI_SLASH_BIT		0x2000	/* for / */
122*2882Svi117747 #define	SIP_URI_VISUALSEP_BIT		0x4000	/* for -.() */
123*2882Svi117747 #define	SIP_URI_DTMFURI_DIGIT_BIT	0x8000	/* for *ABCD */
124*2882Svi117747 
125*2882Svi117747 #define	a 			SIP_URI_ALPHA_BIT
126*2882Svi117747 #define	d 			SIP_URI_DIGIT_BIT
127*2882Svi117747 #define	s 			SIP_URI_SCHEME_BIT
128*2882Svi117747 #define	t 			SIP_URI_TOKEN_BIT
129*2882Svi117747 #define	q 			SIP_URI_QUEST_BIT
130*2882Svi117747 #define	m 			SIP_URI_AT_BIT
131*2882Svi117747 #define	c 			SIP_URI_COLON_BIT
132*2882Svi117747 #define	i 			SIP_URI_SEMI_BIT
133*2882Svi117747 #define	h 			SIP_URI_DASH_BIT
134*2882Svi117747 #define	k 			SIP_URI_MARK_BIT
135*2882Svi117747 #define	n 			SIP_URI_AND_BIT
136*2882Svi117747 #define	o 			SIP_URI_PHCOMM_BIT
137*2882Svi117747 #define	r 			SIP_URI_OTHER_BIT
138*2882Svi117747 #define	l 			SIP_URI_SLASH_BIT
139*2882Svi117747 #define	v 			SIP_URI_VISUALSEP_BIT
140*2882Svi117747 #define	f 			SIP_URI_DTMFURI_DIGIT_BIT
141*2882Svi117747 
142*2882Svi117747 static const unsigned short sip_uri_table[256] = {
143*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
144*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
145*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
146*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
147*2882Svi117747 	0,	t|k,	0,	0,	o|r,	t,	n,	t|k,
148*2882Svi117747 	k|v,	k|v,	t|k|f, s|t|r|o,	r,  h|s|t|k|v, s|t|k|v,	o|l,
149*2882Svi117747 	d,	d,	d,	d,	d,	d,	d,	d,
150*2882Svi117747 	d,	d,	c|o,	i,	0,	r,	0,	q,
151*2882Svi117747 	m,	a|f,	a|f,	a|f,	a|f,	a,	a,	a,
152*2882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
153*2882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
154*2882Svi117747 	a,	a,	a,	o,	0,	o,	0,	t|k,
155*2882Svi117747 	t,	a,	a,	a,	a,	a,	a,	a,
156*2882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
157*2882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
158*2882Svi117747 	a,	a,	a,	0,	0,	0,	t|k,	0,
159*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
160*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
161*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
162*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
163*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
164*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
165*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
166*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
167*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
168*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
169*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
170*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
171*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
172*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
173*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
174*2882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
175*2882Svi117747 };
176*2882Svi117747 
177*2882Svi117747 #undef	a
178*2882Svi117747 #undef	d
179*2882Svi117747 #undef	s
180*2882Svi117747 #undef	t
181*2882Svi117747 #undef	q
182*2882Svi117747 #undef	m
183*2882Svi117747 #undef	c
184*2882Svi117747 #undef	i
185*2882Svi117747 #undef	h
186*2882Svi117747 #undef	k
187*2882Svi117747 #undef	n
188*2882Svi117747 #undef	o
189*2882Svi117747 #undef	r
190*2882Svi117747 #undef	l
191*2882Svi117747 #undef	v
192*2882Svi117747 #undef	f
193*2882Svi117747 
194*2882Svi117747 #define	SIP_URI_UT(c)			sip_uri_table[(unsigned char)(c)]
195*2882Svi117747 #define	SIP_URI_ISALPHA(c)		(SIP_URI_UT(c) & SIP_URI_ALPHA_BIT)
196*2882Svi117747 #define	SIP_URI_ISDIGIT(c)		(SIP_URI_UT(c) & SIP_URI_DIGIT_BIT)
197*2882Svi117747 #define	SIP_URI_ISALNUM(c)		(SIP_URI_UT(c) & SIP_URI_ALNUM_BITS)
198*2882Svi117747 #define	SIP_URI_ISSCHEME(c)		\
199*2882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_SCHEME_BIT))
200*2882Svi117747 #define	SIP_URI_ISTOKEN(c)		\
201*2882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_TOKEN_BIT))
202*2882Svi117747 #define	SIP_URI_ISSIPDELIM(c)		\
203*2882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
204*2882Svi117747 #define	SIP_URI_ISSIPHDELIM(c)					\
205*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
206*2882Svi117747 #define	SIP_URI_ISHOST(c)		\
207*2882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_DASH_BIT))
208*2882Svi117747 #define	SIP_URI_ISUSER(c)						\
209*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|		\
210*2882Svi117747 	SIP_URI_QUEST_BIT|SIP_URI_SLASH_BIT|SIP_URI_AND_BIT))
211*2882Svi117747 
212*2882Svi117747 #define	SIP_URI_ISABSHDELIM(c)					\
213*2882Svi117747 	(SIP_URI_UT(c) & \
214*2882Svi117747 	(SIP_URI_SLASH_BIT|SIP_URI_COLON_BIT|SIP_URI_QUEST_BIT))
215*2882Svi117747 #define	SIP_URI_ISABSDELIM(c)	\
216*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_SLASH_BIT|SIP_URI_QUEST_BIT))
217*2882Svi117747 #define	SIP_URI_ISUNRESERVED(c)	\
218*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
219*2882Svi117747 #define	SIP_URI_ISPARAM(c)						\
220*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_AND_BIT|\
221*2882Svi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
222*2882Svi117747 #define	SIP_URI_ISHEADER(c)						\
223*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_QUEST_BIT|\
224*2882Svi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
225*2882Svi117747 #define	SIP_URI_ISOTHER(c)		(SIP_URI_UT(c) & SIP_URI_OTHER_BIT)
226*2882Svi117747 #define	SIP_URI_ISRESERVED(c)					\
227*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_SLASH_BIT|	\
228*2882Svi117747 	SIP_URI_QUEST_BIT| SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
229*2882Svi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
230*2882Svi117747 #define	SIP_URI_ISPCHAR(c)	\
231*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
232*2882Svi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
233*2882Svi117747 #define	SIP_URI_ISREGNAME(c)					\
234*2882Svi117747 	(SIP_URI_UT(c) & 	\
235*2882Svi117747 	(SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|SIP_URI_COLON_BIT|	\
236*2882Svi117747 	SIP_URI_AT_BIT|SIP_URI_AND_BIT))
237*2882Svi117747 #define	SIP_URI_ISPHONEDIGIT(c)	\
238*2882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_DIGIT_BIT|SIP_URI_VISUALSEP_BIT))
239*2882Svi117747 #define	SIP_URI_ISDTMFDIGIT(c)	(SIP_URI_UT(c) & SIP_URI_DTMFURI_DIGIT_BIT)
240*2882Svi117747 
241*2882Svi117747 static int  sip_uri_url_casecmp(const char *, const char *, unsigned);
242*2882Svi117747 static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
243*2882Svi117747 static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
244*2882Svi117747 static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
245*2882Svi117747 static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
246*2882Svi117747 static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
247*2882Svi117747 static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
248*2882Svi117747 static int  sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
249*2882Svi117747 static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
250*2882Svi117747 static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
251*2882Svi117747 static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
252*2882Svi117747 static void sip_uri_parse_netpath(_sip_uri_t *, char **, char *, boolean_t);
253*2882Svi117747 static int  sip_uri_parse_ipv6(char *, char *);
254*2882Svi117747 static int  sip_uri_parse_ipv4(char *, char *);
255*2882Svi117747 static int  sip_uri_parse_hostname(char *, char *);
256*2882Svi117747 static int sip_uri_parse_tel(char *, char *);
257*2882Svi117747 static int sip_uri_parse_tel_areaspe(char *, char *);
258*2882Svi117747 static int sip_uri_parse_tel_servicepro(char *, char *);
259*2882Svi117747 static int sip_uri_parse_tel_futureext(char *, char *);
260*2882Svi117747 static int sip_uri_isTokenchar(char **, char *);
261*2882Svi117747 static int sip_uri_isEscapedPound(char **, char *);
262*2882Svi117747 static int sip_uri_hexVal(char *, char *);
263*2882Svi117747 static int SIP_URI_HEXVAL(int);
264*2882Svi117747 
265*2882Svi117747 /*
266*2882Svi117747  * get the hex value of a char
267*2882Svi117747  */
268*2882Svi117747 static int
269*2882Svi117747 SIP_URI_HEXVAL(int c)
270*2882Svi117747 {
271*2882Svi117747 	if (c >= 0x30 && c <= 0x39)
272*2882Svi117747 		return (c - '0');
273*2882Svi117747 	if (c >= 0x41 && c <= 0x46)
274*2882Svi117747 		return (c - 'A' + 10);
275*2882Svi117747 	if (c >= 0x61 && c <= 0x66)
276*2882Svi117747 		return (c - 'a' + 10);
277*2882Svi117747 	return (c);
278*2882Svi117747 }
279*2882Svi117747 
280*2882Svi117747 /*
281*2882Svi117747  * basic ASCII case-insensitive comparison
282*2882Svi117747  */
283*2882Svi117747 static int
284*2882Svi117747 sip_uri_url_casecmp(const char *str1, const char *str2, unsigned len)
285*2882Svi117747 {
286*2882Svi117747 	unsigned	j;
287*2882Svi117747 
288*2882Svi117747 	for (j = 0; j < len && tolower(str1[j]) == tolower(str2[j]) &&
289*2882Svi117747 	    str1[j] != '\0'; ++j) {
290*2882Svi117747 		;
291*2882Svi117747 	}
292*2882Svi117747 	return (j == len ? 0 : tolower(str2[j]) - tolower(str1[j]));
293*2882Svi117747 }
294*2882Svi117747 
295*2882Svi117747 /*
296*2882Svi117747  * telephone-subscriber  = global-phone-number / local-phone-number
297*2882Svi117747  * Please refer to RFC 2806
298*2882Svi117747  */
299*2882Svi117747 static int
300*2882Svi117747 sip_uri_parse_tel(char *scan, char *uend)
301*2882Svi117747 {
302*2882Svi117747 	char	*mark = (char *)0;
303*2882Svi117747 	int	ret = 0;
304*2882Svi117747 	int	isGlobal = 0;
305*2882Svi117747 	int	quote = 0;
306*2882Svi117747 
307*2882Svi117747 	if (scan == uend)
308*2882Svi117747 		return (0);
309*2882Svi117747 	if (*scan == '+') {
310*2882Svi117747 		++scan;
311*2882Svi117747 		isGlobal = 1;
312*2882Svi117747 	}
313*2882Svi117747 	mark = scan;
314*2882Svi117747 	if (isGlobal) {
315*2882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
316*2882Svi117747 			++scan;
317*2882Svi117747 	} else {
318*2882Svi117747 		while (scan < uend &&
319*2882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
320*2882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
321*2882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
322*2882Svi117747 		    *scan == 'p' || *scan == 'w')) {
323*2882Svi117747 			++scan;
324*2882Svi117747 		}
325*2882Svi117747 	}
326*2882Svi117747 	if (mark == scan || (scan < uend && *scan != ';'))
327*2882Svi117747 		return (0);
328*2882Svi117747 
329*2882Svi117747 	/*
330*2882Svi117747 	 * parse isdn-subaddress
331*2882Svi117747 	 */
332*2882Svi117747 	if (uend - scan > 6 && !sip_uri_url_casecmp(scan, ";isub=", 6)) {
333*2882Svi117747 		scan += 6;
334*2882Svi117747 		mark = scan;
335*2882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
336*2882Svi117747 			++scan;
337*2882Svi117747 		if (mark == scan || (scan < uend && *scan != ';'))
338*2882Svi117747 			return (0);
339*2882Svi117747 	}
340*2882Svi117747 
341*2882Svi117747 	/*
342*2882Svi117747 	 * parse post-dial
343*2882Svi117747 	 */
344*2882Svi117747 	if (uend - scan > 7 && !sip_uri_url_casecmp(scan, ";postd=", 7)) {
345*2882Svi117747 		scan += 7;
346*2882Svi117747 		mark = scan;
347*2882Svi117747 		while (scan < uend &&
348*2882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
349*2882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
350*2882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
351*2882Svi117747 		    *scan == 'p' || *scan == 'w')) {
352*2882Svi117747 			++scan;
353*2882Svi117747 		}
354*2882Svi117747 		if (mark == scan || (scan < uend && *scan != ';'))
355*2882Svi117747 			return (0);
356*2882Svi117747 	}
357*2882Svi117747 
358*2882Svi117747 	if (!isGlobal) {
359*2882Svi117747 		/*
360*2882Svi117747 		 * parse area-specifier
361*2882Svi117747 		 */
362*2882Svi117747 		if (uend - scan > 15 &&
363*2882Svi117747 		    !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
364*2882Svi117747 			scan += 15;
365*2882Svi117747 			mark = scan;
366*2882Svi117747 			while (scan < uend && *scan != ';')
367*2882Svi117747 				++scan;
368*2882Svi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
369*2882Svi117747 		}
370*2882Svi117747 	} else {
371*2882Svi117747 		ret = 1;
372*2882Svi117747 	}
373*2882Svi117747 
374*2882Svi117747 	/*
375*2882Svi117747 	 * parse area-specifier, service-provider, future-extension
376*2882Svi117747 	 */
377*2882Svi117747 	while (scan < uend && ret) {
378*2882Svi117747 		if (uend - scan > 15 &&
379*2882Svi117747 			!sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
380*2882Svi117747 			scan += 15;
381*2882Svi117747 			mark = scan;
382*2882Svi117747 			while (scan < uend && *scan != ';')
383*2882Svi117747 				++scan;
384*2882Svi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
385*2882Svi117747 		} else if (uend - scan > 5 &&
386*2882Svi117747 		    !sip_uri_url_casecmp(scan, ";tsp=", 5)) {
387*2882Svi117747 			scan += 5;
388*2882Svi117747 			mark = scan;
389*2882Svi117747 			while (scan < uend && *scan != ';')
390*2882Svi117747 				++scan;
391*2882Svi117747 			ret = sip_uri_parse_tel_servicepro(mark, scan);
392*2882Svi117747 		} else {
393*2882Svi117747 			++scan;
394*2882Svi117747 			mark = scan;
395*2882Svi117747 			while (scan < uend && (*scan != ';' || quote)) {
396*2882Svi117747 				if (sip_uri_hexVal(scan, uend) == 0x22) {
397*2882Svi117747 					quote = !quote;
398*2882Svi117747 					scan += 3;
399*2882Svi117747 				} else {
400*2882Svi117747 					++scan;
401*2882Svi117747 				}
402*2882Svi117747 			}
403*2882Svi117747 			ret = sip_uri_parse_tel_futureext(mark, scan);
404*2882Svi117747 		}
405*2882Svi117747 	}
406*2882Svi117747 	return (ret && scan == uend);
407*2882Svi117747 }
408*2882Svi117747 
409*2882Svi117747 /*
410*2882Svi117747  * area-specifier        = ";" phone-context-tag "=" phone-context-ident
411*2882Svi117747  * phone-context-tag     = "phone-context"
412*2882Svi117747  * phone-context-ident   = network-prefix / private-prefix
413*2882Svi117747  * network-prefix        = global-network-prefix / local-network-prefix
414*2882Svi117747  * global-network-prefix = "+" 1*phonedigit
415*2882Svi117747  * local-network-prefix  = 1*(phonedigit / dtmf-digit / pause-character)
416*2882Svi117747  * private-prefix        = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
417*2882Svi117747  *                          %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
418*2882Svi117747  *                          %x65-6F / %x71-76 / %x78-7E)
419*2882Svi117747  *                          *(%x21-3A / %x3C-7E)
420*2882Svi117747  * phonedigit            = DIGIT / visual-separator
421*2882Svi117747  * visual-separator      = "-" / "." / "(" / ")"
422*2882Svi117747  * pause-character       = one-second-pause / wait-for-dial-tone
423*2882Svi117747  * one-second-pause      = "p"
424*2882Svi117747  * wait-for-dial-tone    = "w"
425*2882Svi117747  * dtmf-digit            = "*" / "#" / "A" / "B" / "C" / "D"
426*2882Svi117747  */
427*2882Svi117747 static int
428*2882Svi117747 sip_uri_parse_tel_areaspe(char *scan, char *uend)
429*2882Svi117747 {
430*2882Svi117747 	int	uri_hexValue;
431*2882Svi117747 
432*2882Svi117747 	if (scan == uend)
433*2882Svi117747 		return (0);
434*2882Svi117747 
435*2882Svi117747 	/*
436*2882Svi117747 	 * parse global-network-prefix
437*2882Svi117747 	 */
438*2882Svi117747 	if (*scan == '+') {
439*2882Svi117747 		++scan;
440*2882Svi117747 		if (scan == uend)
441*2882Svi117747 			return (0);
442*2882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
443*2882Svi117747 			++scan;
444*2882Svi117747 	/*
445*2882Svi117747 	 * parse local-network-prefix
446*2882Svi117747 	 */
447*2882Svi117747 	} else if (SIP_URI_ISPHONEDIGIT(*scan) || SIP_URI_ISDTMFDIGIT(*scan) ||
448*2882Svi117747 	    sip_uri_isEscapedPound(&scan, uend) ||
449*2882Svi117747 	    *scan == 'p' || *scan == 'w') {
450*2882Svi117747 		++scan;
451*2882Svi117747 		while (scan < uend &&
452*2882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
453*2882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
454*2882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
455*2882Svi117747 		    *scan == 'p' || *scan == 'w')) {
456*2882Svi117747 			++scan;
457*2882Svi117747 		}
458*2882Svi117747 	} else {
459*2882Svi117747 	/*
460*2882Svi117747 	 * parse private-prefix
461*2882Svi117747 	 *
462*2882Svi117747 	 * any characters allowed in RFC 2806 that are not allowed in
463*2882Svi117747 	 * the user part of the SIP URI MUST be escaped
464*2882Svi117747 	 *
465*2882Svi117747 	 * private-prefix	= (! $ & ', / = ? _
466*2882Svi117747 	 *			EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
467*2882Svi117747 	 *			{ } | ~ [ ] \ ^  ` " % : < > @)
468*2882Svi117747 	 *			*(%x21-3A / %x3C-7E)
469*2882Svi117747 	 *
470*2882Svi117747 	 * following characters are allowed in RFC 2806 and
471*2882Svi117747 	 * the user part of SIP URI
472*2882Svi117747 	 *  ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
473*2882Svi117747 	 */
474*2882Svi117747 		if (*scan == '!' || *scan == '$' || *scan == '&' ||
475*2882Svi117747 		    *scan == '\'' || *scan == ',' || *scan == '/' ||
476*2882Svi117747 		    *scan == '=' || *scan == '?' || *scan == '_' ||
477*2882Svi117747 		    (*scan >= 'E' && *scan <= 'Z' &&
478*2882Svi117747 		    *scan != 'P' && *scan != 'W') ||
479*2882Svi117747 		    (*scan >= 'e' && *scan <= 'z' &&
480*2882Svi117747 		    *scan != 'p' && *scan != 'w')) {
481*2882Svi117747 			++scan;
482*2882Svi117747 		} else {
483*2882Svi117747 			uri_hexValue = sip_uri_hexVal(scan, uend);
484*2882Svi117747 			if (uri_hexValue == 0x21 || uri_hexValue == 0x22 ||
485*2882Svi117747 			    (uri_hexValue >= 0x24 && uri_hexValue <= 0x27) ||
486*2882Svi117747 			    uri_hexValue == 0x2c || uri_hexValue == 0x2f ||
487*2882Svi117747 			    uri_hexValue == 0x3a ||
488*2882Svi117747 			    (uri_hexValue >= 0x3c && uri_hexValue <= 0x40) ||
489*2882Svi117747 			    (uri_hexValue >= 0x45 && uri_hexValue <= 0x4f) ||
490*2882Svi117747 			    (uri_hexValue >= 0x51 && uri_hexValue <= 0x56) ||
491*2882Svi117747 			    (uri_hexValue >= 0x58 && uri_hexValue <= 0x60) ||
492*2882Svi117747 			    (uri_hexValue >= 0x65 && uri_hexValue <= 0x6f) ||
493*2882Svi117747 			    (uri_hexValue >= 0x71 && uri_hexValue <= 0x76) ||
494*2882Svi117747 			    (uri_hexValue >= 0x78 && uri_hexValue <= 0x7e)) {
495*2882Svi117747 				scan += 3;
496*2882Svi117747 			} else {
497*2882Svi117747 				return (0);
498*2882Svi117747 			}
499*2882Svi117747 		}
500*2882Svi117747 		/*
501*2882Svi117747 		 * parse *(%x21-3A / %x3C-7E)
502*2882Svi117747 		 */
503*2882Svi117747 		while (scan < uend) {
504*2882Svi117747 			if (SIP_URI_ISUNRESERVED(*scan) ||
505*2882Svi117747 			    (SIP_URI_ISUSER(*scan) && *scan != ';')) {
506*2882Svi117747 				++scan;
507*2882Svi117747 			} else {
508*2882Svi117747 				uri_hexValue = sip_uri_hexVal(scan, uend);
509*2882Svi117747 				if (uri_hexValue >= 0x21 &&
510*2882Svi117747 				    uri_hexValue <= 0x7e &&
511*2882Svi117747 				    uri_hexValue != 0x3b) {
512*2882Svi117747 					scan += 3;
513*2882Svi117747 				} else {
514*2882Svi117747 					return (0);
515*2882Svi117747 				}
516*2882Svi117747 			}
517*2882Svi117747 		}
518*2882Svi117747 	}
519*2882Svi117747 	if (scan < uend)
520*2882Svi117747 		return (0);
521*2882Svi117747 	return (1);
522*2882Svi117747 }
523*2882Svi117747 
524*2882Svi117747 static int
525*2882Svi117747 sip_uri_hexVal(char *scan, char *uend)
526*2882Svi117747 {
527*2882Svi117747 	int	ret = -1;
528*2882Svi117747 
529*2882Svi117747 	if (SIP_URI_ISURLESCAPE(scan, uend)) {
530*2882Svi117747 		ret = (SIP_URI_ISDIGIT(scan[1]) ? (scan[1] - '0') :
531*2882Svi117747 		    (tolower(scan[1]) - 'a' + 10)) * 16 +
532*2882Svi117747 		    (SIP_URI_ISDIGIT(scan[2]) ? (scan[2] - '0') :
533*2882Svi117747 		    (tolower(scan[2]) - 'a' + 10));
534*2882Svi117747 	}
535*2882Svi117747 	return (ret);
536*2882Svi117747 }
537*2882Svi117747 
538*2882Svi117747 /*
539*2882Svi117747  * service-provider  = ";" provider-tag "=" provider-hostname
540*2882Svi117747  * provider-tag      = "tsp"
541*2882Svi117747  * provider-hostname = domain
542*2882Svi117747  */
543*2882Svi117747 static int
544*2882Svi117747 sip_uri_parse_tel_servicepro(char *scan, char *uend)
545*2882Svi117747 {
546*2882Svi117747 	char	*mark = (char *)0;
547*2882Svi117747 
548*2882Svi117747 	if (scan == uend)
549*2882Svi117747 		return (0);
550*2882Svi117747 
551*2882Svi117747 	/*
552*2882Svi117747 	 * parse domain=" "
553*2882Svi117747 	 */
554*2882Svi117747 	if (sip_uri_hexVal(scan, uend) == 0x20 && scan + 3 == uend)
555*2882Svi117747 		return (1);
556*2882Svi117747 	while (scan < uend) {
557*2882Svi117747 		mark = scan;
558*2882Svi117747 		while (scan < uend && (*scan == '-'|| SIP_URI_ISALNUM(*scan)))
559*2882Svi117747 			++scan;
560*2882Svi117747 		if ((scan < uend && *scan != '.') ||
561*2882Svi117747 		    !SIP_URI_ISALPHA(*mark) || !SIP_URI_ISALNUM(*(scan - 1))) {
562*2882Svi117747 			return (0);
563*2882Svi117747 		}
564*2882Svi117747 		if (scan < uend)
565*2882Svi117747 			++scan;
566*2882Svi117747 	}
567*2882Svi117747 
568*2882Svi117747 	if (scan < uend)
569*2882Svi117747 		return (0);
570*2882Svi117747 	return (1);
571*2882Svi117747 }
572*2882Svi117747 
573*2882Svi117747 /*
574*2882Svi117747  * future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
575*2882Svi117747  *                    ["?" 1*(token-char)]) / quoted-string )]
576*2882Svi117747  * token-char       = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
577*2882Svi117747  *                     / %x41-5A / %x5E-7A / %x7C / %x7E)
578*2882Svi117747  */
579*2882Svi117747 static int
580*2882Svi117747 sip_uri_parse_tel_futureext(char *scan, char *uend)
581*2882Svi117747 {
582*2882Svi117747 	char	*mark;
583*2882Svi117747 	int	uri_hexValue = 0;
584*2882Svi117747 
585*2882Svi117747 	if (scan == uend)
586*2882Svi117747 		return (0);
587*2882Svi117747 
588*2882Svi117747 	/*
589*2882Svi117747 	 * parse 1*(token-char)
590*2882Svi117747 	 */
591*2882Svi117747 	mark = scan;
592*2882Svi117747 	while (scan < uend && sip_uri_isTokenchar(&scan, uend))
593*2882Svi117747 		;
594*2882Svi117747 	if (mark == scan ||
595*2882Svi117747 	    (scan < uend && (*scan != '=' || scan + 1 == uend))) {
596*2882Svi117747 		return (0);
597*2882Svi117747 	}
598*2882Svi117747 	if (scan == uend)
599*2882Svi117747 		return (1);
600*2882Svi117747 	++scan;
601*2882Svi117747 
602*2882Svi117747 	/*
603*2882Svi117747 	 * parse 1*token-char ["?" 1*token-char]
604*2882Svi117747 	 */
605*2882Svi117747 	if (sip_uri_isTokenchar(&scan, uend)) {
606*2882Svi117747 		while (sip_uri_isTokenchar(&scan, uend))
607*2882Svi117747 			;
608*2882Svi117747 		if (scan < uend) {
609*2882Svi117747 			if (*scan != '?')
610*2882Svi117747 				return (0);
611*2882Svi117747 			++scan;
612*2882Svi117747 			mark = scan;
613*2882Svi117747 			while (sip_uri_isTokenchar(&scan, uend))
614*2882Svi117747 				;
615*2882Svi117747 			if (mark == scan)
616*2882Svi117747 				return (0);
617*2882Svi117747 		}
618*2882Svi117747 	} else { /* parse quoted-string */
619*2882Svi117747 		uri_hexValue = sip_uri_hexVal(scan, uend);
620*2882Svi117747 		if (uri_hexValue != 0x22)
621*2882Svi117747 			return (0);
622*2882Svi117747 		scan += 3;
623*2882Svi117747 		while (scan < uend && sip_uri_hexVal(scan, uend) != 0x22) {
624*2882Svi117747 			/*
625*2882Svi117747 			 * parse "\" CHAR
626*2882Svi117747 			 */
627*2882Svi117747 			if (sip_uri_hexVal(scan, uend) == 0x5c) {
628*2882Svi117747 				scan += 3;
629*2882Svi117747 				if (scan < uend) {
630*2882Svi117747 					if (SIP_URI_ISUNRESERVED(*scan) ||
631*2882Svi117747 					    SIP_URI_ISUSER(*scan)) {
632*2882Svi117747 						++scan;
633*2882Svi117747 					} else if (sip_uri_hexVal(scan, uend) >=
634*2882Svi117747 					    0x00 &&
635*2882Svi117747 					    sip_uri_hexVal(scan, uend) <=
636*2882Svi117747 					    0x7f) {
637*2882Svi117747 						scan += 3;
638*2882Svi117747 					} else {
639*2882Svi117747 						return (0);
640*2882Svi117747 					}
641*2882Svi117747 				} else {
642*2882Svi117747 					return (0);
643*2882Svi117747 				}
644*2882Svi117747 			} else {
645*2882Svi117747 				if (SIP_URI_ISUNRESERVED(*scan) ||
646*2882Svi117747 				    SIP_URI_ISUSER(*scan)) {
647*2882Svi117747 					++scan;
648*2882Svi117747 				} else {
649*2882Svi117747 					uri_hexValue =
650*2882Svi117747 					    sip_uri_hexVal(scan, uend);
651*2882Svi117747 					if ((uri_hexValue >= 0x20 &&
652*2882Svi117747 						uri_hexValue <= 0x21) ||
653*2882Svi117747 						(uri_hexValue >= 0x23 &&
654*2882Svi117747 						uri_hexValue <= 0x7e) ||
655*2882Svi117747 						(uri_hexValue >= 0x80 &&
656*2882Svi117747 						uri_hexValue <= 0xff)) {
657*2882Svi117747 						scan += 3;
658*2882Svi117747 					} else {
659*2882Svi117747 						return (0);
660*2882Svi117747 					}
661*2882Svi117747 				}
662*2882Svi117747 			}
663*2882Svi117747 		}
664*2882Svi117747 		if (scan == uend ||
665*2882Svi117747 		    (scan < uend && sip_uri_hexVal(scan, uend) != 0x22)) {
666*2882Svi117747 			return (0);
667*2882Svi117747 		}
668*2882Svi117747 		scan += 3;
669*2882Svi117747 	}
670*2882Svi117747 
671*2882Svi117747 	if (scan < uend)
672*2882Svi117747 		return (0);
673*2882Svi117747 	return (1);
674*2882Svi117747 }
675*2882Svi117747 
676*2882Svi117747 /*
677*2882Svi117747  * Any characters allowed in RFC2806 tel URL that are not allowed in
678*2882Svi117747  * the user part of the SIP URI MUST be escaped.
679*2882Svi117747  * token-char = - _ . ! ~ * ' $ &  + DIGIT ALPHA #  % ^ ` |
680*2882Svi117747  */
681*2882Svi117747 static int
682*2882Svi117747 sip_uri_isTokenchar(char **pscan, char *uend)
683*2882Svi117747 {
684*2882Svi117747 	char	*scan = *pscan;
685*2882Svi117747 	int	uri_hexValue = 0;
686*2882Svi117747 
687*2882Svi117747 	if (scan == uend)
688*2882Svi117747 		return (0);
689*2882Svi117747 
690*2882Svi117747 	/*
691*2882Svi117747 	 * for ALPAH DIGIT - _ . ! ~ * ' $ & +
692*2882Svi117747 	 */
693*2882Svi117747 	if ((SIP_URI_ISUNRESERVED(*scan) && *scan != '(' && *scan != ')') ||
694*2882Svi117747 	    *scan == '$' || *scan == '&' || *scan == '+') {
695*2882Svi117747 		++scan;
696*2882Svi117747 		*pscan = scan;
697*2882Svi117747 		return (1);
698*2882Svi117747 	}
699*2882Svi117747 
700*2882Svi117747 	uri_hexValue = sip_uri_hexVal(scan, uend);
701*2882Svi117747 	if (uri_hexValue == 0x21 || uri_hexValue == 0x7c ||
702*2882Svi117747 	    uri_hexValue == 0x7e ||
703*2882Svi117747 	    (uri_hexValue >= 0x23 && uri_hexValue <= 0x27) ||
704*2882Svi117747 	    (uri_hexValue >= 0x2a && uri_hexValue <= 0x2b) ||
705*2882Svi117747 	    (uri_hexValue >= 0x2d && uri_hexValue <= 0x2e) ||
706*2882Svi117747 	    (uri_hexValue >= 0x30 && uri_hexValue <= 0x39) ||
707*2882Svi117747 	    (uri_hexValue >= 0x41 && uri_hexValue <= 0x5a) ||
708*2882Svi117747 	    (uri_hexValue >= 0x5e && uri_hexValue <= 0x7a)) {
709*2882Svi117747 		scan += 3;
710*2882Svi117747 		*pscan = scan;
711*2882Svi117747 		return (1);
712*2882Svi117747 	}
713*2882Svi117747 	return (0);
714*2882Svi117747 }
715*2882Svi117747 
716*2882Svi117747 /*
717*2882Svi117747  * '#' is not allowed in the telephone-subscriber part of SIP URI
718*2882Svi117747  * it must be escaped
719*2882Svi117747  */
720*2882Svi117747 static int
721*2882Svi117747 sip_uri_isEscapedPound(char **pscan, char *uend)
722*2882Svi117747 {
723*2882Svi117747 	char	*scan = *pscan;
724*2882Svi117747 
725*2882Svi117747 	if (scan == uend)
726*2882Svi117747 		return (0);
727*2882Svi117747 	if (*scan == '%' && scan + 2 < uend && scan[1] == '2' &&
728*2882Svi117747 	    scan[2] == '3') {
729*2882Svi117747 		scan += 2;
730*2882Svi117747 		*pscan = scan;
731*2882Svi117747 		return (1);
732*2882Svi117747 	}
733*2882Svi117747 	return (0);
734*2882Svi117747 }
735*2882Svi117747 
736*2882Svi117747 /*
737*2882Svi117747  * scheme =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
738*2882Svi117747  */
739*2882Svi117747 static int
740*2882Svi117747 sip_uri_parse_scheme(_sip_uri_t *outurl, char *scan, char *uend)
741*2882Svi117747 {
742*2882Svi117747 	if (scan == uend) {
743*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
744*2882Svi117747 		return (0);
745*2882Svi117747 	}
746*2882Svi117747 	outurl->sip_uri_scheme.sip_str_ptr = scan;
747*2882Svi117747 	outurl->sip_uri_scheme.sip_str_len = uend - scan;
748*2882Svi117747 
749*2882Svi117747 	if (scan < uend && SIP_URI_ISALPHA(*scan)) {
750*2882Svi117747 		++scan;
751*2882Svi117747 		while (scan < uend && SIP_URI_ISSCHEME(*scan))
752*2882Svi117747 			++scan;
753*2882Svi117747 	}
754*2882Svi117747 	if (scan < uend)
755*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
756*2882Svi117747 	return (1);
757*2882Svi117747 }
758*2882Svi117747 
759*2882Svi117747 /*
760*2882Svi117747  * The format of params is supposed to be;XXX;XXX;XXX
761*2882Svi117747  * uri-parameters	= *(";" uri-parameter)
762*2882Svi117747  * uri-parameter	= transport-param / user-param / method-param
763*2882Svi117747  * 			/ ttl-param / maddr-param / lr-param / other-param
764*2882Svi117747  * transport-param	=  "transport="
765*2882Svi117747  *			("udp" / "tcp" / "sctp" / "tls" / other-transport)
766*2882Svi117747  * other-transport		=  token
767*2882Svi117747  * user-param		=  "user=" ("phone" / "ip" / other-user)
768*2882Svi117747  * other-user		=  token
769*2882Svi117747  * method-param		=  "method=" Method
770*2882Svi117747  * ttl-param		=  "ttl=" ttl
771*2882Svi117747  * maddr-param		=  "maddr=" host
772*2882Svi117747  * lr-param		=  "lr"
773*2882Svi117747  * other-param		=  pname [ "=" pvalue ]
774*2882Svi117747  * pname		=  1*paramchar
775*2882Svi117747  * pvalue		=  1*paramchar
776*2882Svi117747  * paramchar		=  param-unreserved / unreserved / escaped
777*2882Svi117747  * param-unreserved	=  "[" / "]" / "/" / ":" / "&" / "+" / "$"
778*2882Svi117747  */
779*2882Svi117747 static void
780*2882Svi117747 sip_uri_parse_params(_sip_uri_t *outurl, char *scan, char *uend)
781*2882Svi117747 {
782*2882Svi117747 	char		*mark = (char *)0;
783*2882Svi117747 	char		*equal = (char *)0;
784*2882Svi117747 	int		i = 0;
785*2882Svi117747 	int		ttl = 0;
786*2882Svi117747 	int		paramleftlen = 0;
787*2882Svi117747 	int		gothost = 0;
788*2882Svi117747 	sip_param_t	*param = NULL;
789*2882Svi117747 	sip_param_t	*new_param = NULL;
790*2882Svi117747 
791*2882Svi117747 	if (scan == uend || *scan != ';' || scan + 1 == uend) {
792*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
793*2882Svi117747 		return;
794*2882Svi117747 	}
795*2882Svi117747 
796*2882Svi117747 	while (scan < uend) {
797*2882Svi117747 		mark = ++scan;
798*2882Svi117747 		while (scan < uend && *scan != ';')
799*2882Svi117747 			++scan;
800*2882Svi117747 		if (scan == mark) {
801*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
802*2882Svi117747 			return;
803*2882Svi117747 		}
804*2882Svi117747 
805*2882Svi117747 		new_param = calloc(1, sizeof (sip_param_t));
806*2882Svi117747 		if (new_param == NULL) {
807*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_MEMORY;
808*2882Svi117747 			return;
809*2882Svi117747 		}
810*2882Svi117747 
811*2882Svi117747 		if (param == NULL)
812*2882Svi117747 			outurl->sip_uri_params = new_param;
813*2882Svi117747 		else
814*2882Svi117747 			param->param_next = new_param;
815*2882Svi117747 
816*2882Svi117747 		param = new_param;
817*2882Svi117747 
818*2882Svi117747 		param->param_name.sip_str_ptr = mark;
819*2882Svi117747 		equal = memchr(mark, '=', scan - mark);
820*2882Svi117747 		if (equal == (char *)0) {
821*2882Svi117747 			param->param_name.sip_str_len = scan - mark;
822*2882Svi117747 			param->param_value.sip_str_ptr = NULL;
823*2882Svi117747 			param->param_value.sip_str_len = 0;
824*2882Svi117747 			while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
825*2882Svi117747 			    SIP_URI_ISURLESCAPE(mark, scan))) {
826*2882Svi117747 				++mark;
827*2882Svi117747 			}
828*2882Svi117747 		} else {
829*2882Svi117747 			param->param_name.sip_str_len = equal - mark;
830*2882Svi117747 			param->param_value.sip_str_ptr = equal + 1;
831*2882Svi117747 			param->param_value.sip_str_len = scan - equal - 1;
832*2882Svi117747 
833*2882Svi117747 			if (mark == equal || equal + 1 == scan) {
834*2882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
835*2882Svi117747 				return;
836*2882Svi117747 			}
837*2882Svi117747 			paramleftlen = equal - mark + 1;
838*2882Svi117747 			if ((paramleftlen == 10 &&
839*2882Svi117747 			    !sip_uri_url_casecmp(mark, "transport=", 10)) ||
840*2882Svi117747 			    (paramleftlen == 5 &&
841*2882Svi117747 			    !sip_uri_url_casecmp(mark, "user=", 5)) ||
842*2882Svi117747 			    (paramleftlen == 7 &&
843*2882Svi117747 			    !sip_uri_url_casecmp(mark, "method=", 7))) {
844*2882Svi117747 				if (scan - equal == 1) {
845*2882Svi117747 					outurl->sip_uri_errflags |=
846*2882Svi117747 					    SIP_URIERR_PARAM;
847*2882Svi117747 					return;
848*2882Svi117747 				}
849*2882Svi117747 				mark = equal + 1;
850*2882Svi117747 				while (mark < scan && SIP_URI_ISTOKEN(*mark))
851*2882Svi117747 					++mark;
852*2882Svi117747 			} else if (paramleftlen == 4 &&
853*2882Svi117747 			    !sip_uri_url_casecmp(mark, "ttl=", 4)) {
854*2882Svi117747 				if (scan - equal == 1) {
855*2882Svi117747 					outurl->sip_uri_errflags |=
856*2882Svi117747 					    SIP_URIERR_PARAM;
857*2882Svi117747 					return;
858*2882Svi117747 				}
859*2882Svi117747 				mark = equal;
860*2882Svi117747 				for (i = 0; i < 3; ++i) {
861*2882Svi117747 					++mark;
862*2882Svi117747 					if (mark < scan &&
863*2882Svi117747 					    SIP_URI_ISDIGIT(*mark)) {
864*2882Svi117747 						ttl = ttl * 10 + (*mark - '0');
865*2882Svi117747 					}
866*2882Svi117747 					if (ttl > 255) {
867*2882Svi117747 						outurl->sip_uri_errflags |=
868*2882Svi117747 							SIP_URIERR_PARAM;
869*2882Svi117747 						return;
870*2882Svi117747 					}
871*2882Svi117747 				}
872*2882Svi117747 			} else if (paramleftlen == 6 &&
873*2882Svi117747 			    !sip_uri_url_casecmp(mark, "maddr=", 6)) {
874*2882Svi117747 				gothost = 0;
875*2882Svi117747 				mark = equal + 1;
876*2882Svi117747 				if (mark < scan && SIP_URI_ISDIGIT(*mark)) {
877*2882Svi117747 					gothost = sip_uri_parse_ipv4(mark,
878*2882Svi117747 					    scan);
879*2882Svi117747 				}
880*2882Svi117747 				/*
881*2882Svi117747 				 * not valid syntax for a host or user name,
882*2882Svi117747 				 * try IPv6 literal
883*2882Svi117747 				 */
884*2882Svi117747 				if (!gothost && mark < scan && *mark == '[') {
885*2882Svi117747 					gothost = sip_uri_parse_ipv6(mark,
886*2882Svi117747 					    scan);
887*2882Svi117747 				}
888*2882Svi117747 				/*
889*2882Svi117747 				 * look for a valid host name:
890*2882Svi117747 				 * *(domainlabel ".") toplabel ["."]
891*2882Svi117747 				 */
892*2882Svi117747 				if (!gothost && mark < scan) {
893*2882Svi117747 					if (!(gothost =
894*2882Svi117747 					    sip_uri_parse_hostname(mark,
895*2882Svi117747 					    scan))) {
896*2882Svi117747 						outurl->sip_uri_errflags |=
897*2882Svi117747 							SIP_URIERR_PARAM;
898*2882Svi117747 					}
899*2882Svi117747 				}
900*2882Svi117747 				if (gothost)
901*2882Svi117747 					mark = scan;
902*2882Svi117747 			} else if (paramleftlen == 3 &&
903*2882Svi117747 			    !sip_uri_url_casecmp(mark, "lr=", 3)) {
904*2882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
905*2882Svi117747 				return;
906*2882Svi117747 			} else {
907*2882Svi117747 				while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
908*2882Svi117747 				    SIP_URI_ISURLESCAPE(mark, scan) ||
909*2882Svi117747 				    mark == equal)) {
910*2882Svi117747 					++mark;
911*2882Svi117747 				}
912*2882Svi117747 			}
913*2882Svi117747 		}
914*2882Svi117747 		if (mark < scan) {
915*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
916*2882Svi117747 			return;
917*2882Svi117747 		}
918*2882Svi117747 	}
919*2882Svi117747 }
920*2882Svi117747 
921*2882Svi117747 /*
922*2882Svi117747  * The format of headers is supposed to be ?XXX&XXX&XXX
923*2882Svi117747  * headers         =  "?" header *("&" header
924*2882Svi117747  * header          =  hname "=" hvalue
925*2882Svi117747  * hname           =  1*(hnv-unreserved / unreserved / escaped
926*2882Svi117747  * hvalue          =  *(hnv-unreserved / unreserved / escaped
927*2882Svi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
928*2882Svi117747  */
929*2882Svi117747 static void
930*2882Svi117747 sip_uri_parse_headers(_sip_uri_t *outurl, char *scan, char *uend)
931*2882Svi117747 {
932*2882Svi117747 	char	*mark = NULL;
933*2882Svi117747 	char	*equal = NULL;
934*2882Svi117747 
935*2882Svi117747 	if (scan == uend || *scan != '?' || scan + 1 == uend) {
936*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
937*2882Svi117747 		return;
938*2882Svi117747 	}
939*2882Svi117747 	outurl->sip_uri_headers.sip_str_ptr = scan + 1;
940*2882Svi117747 	outurl->sip_uri_headers.sip_str_len = uend - (scan + 1);
941*2882Svi117747 
942*2882Svi117747 	while (scan < uend) {
943*2882Svi117747 		mark = ++scan;
944*2882Svi117747 		while (scan < uend && *scan != '&')
945*2882Svi117747 			++scan;
946*2882Svi117747 		if (scan == mark) {
947*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
948*2882Svi117747 			return;
949*2882Svi117747 		}
950*2882Svi117747 		equal = memchr(mark, '=', scan - mark);
951*2882Svi117747 		if (equal == mark || equal == (char *)0) {
952*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
953*2882Svi117747 			return;
954*2882Svi117747 		}
955*2882Svi117747 		while (mark < scan &&
956*2882Svi117747 		    (SIP_URI_ISHEADER(*mark) ||
957*2882Svi117747 		    SIP_URI_ISURLESCAPE(mark, scan) || mark == equal)) {
958*2882Svi117747 			++mark;
959*2882Svi117747 		}
960*2882Svi117747 		if (mark < scan) {
961*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
962*2882Svi117747 			return;
963*2882Svi117747 		}
964*2882Svi117747 	}
965*2882Svi117747 }
966*2882Svi117747 
967*2882Svi117747 /*
968*2882Svi117747  * opaque-part   =  uric-no-slash *uric
969*2882Svi117747  * uric          =  reserved / unreserved / escaped
970*2882Svi117747  * uric-no-slash =  unreserved / escaped / ";" / "?" / ":" / "@"
971*2882Svi117747  *                  / "&" / "=" / "+" / "$" / ","
972*2882Svi117747  */
973*2882Svi117747 static void
974*2882Svi117747 sip_uri_parse_abs_opaque(_sip_uri_t *outurl, char *scan, char *uend)
975*2882Svi117747 {
976*2882Svi117747 	if (scan == uend) {
977*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
978*2882Svi117747 		return;
979*2882Svi117747 	}
980*2882Svi117747 	outurl->sip_uri_opaque.sip_str_ptr = scan;
981*2882Svi117747 	outurl->sip_uri_opaque.sip_str_len = uend - scan;
982*2882Svi117747 
983*2882Svi117747 	if (SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
984*2882Svi117747 	    SIP_URI_ISOTHER(*scan) || *scan == ';' || *scan == '?' ||
985*2882Svi117747 	    *scan == ':' || *scan == '@' || *scan == '&') {
986*2882Svi117747 		++scan;
987*2882Svi117747 	} else {
988*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
989*2882Svi117747 		return;
990*2882Svi117747 	}
991*2882Svi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
992*2882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
993*2882Svi117747 		++scan;
994*2882Svi117747 	}
995*2882Svi117747 	if (scan < uend)
996*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
997*2882Svi117747 }
998*2882Svi117747 
999*2882Svi117747 /*
1000*2882Svi117747  * format of query is supposed to be ?XXX
1001*2882Svi117747  * query =  *uric
1002*2882Svi117747  * uric  =  reserved / unreserved / escaped
1003*2882Svi117747  */
1004*2882Svi117747 static void
1005*2882Svi117747 sip_uri_parse_abs_query(_sip_uri_t *outurl, char *scan, char *uend)
1006*2882Svi117747 {
1007*2882Svi117747 	if (uend == scan || *scan != '?' || scan + 1 == uend)
1008*2882Svi117747 		return;
1009*2882Svi117747 	++scan;
1010*2882Svi117747 	outurl->sip_uri_query.sip_str_ptr = scan;
1011*2882Svi117747 	outurl->sip_uri_query.sip_str_len = uend - scan;
1012*2882Svi117747 
1013*2882Svi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
1014*2882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
1015*2882Svi117747 		++scan;
1016*2882Svi117747 	}
1017*2882Svi117747 	if (scan < uend)
1018*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_QUERY;
1019*2882Svi117747 }
1020*2882Svi117747 
1021*2882Svi117747 /*
1022*2882Svi117747  * the format of path is supposed to be /XXX;XXX/XXX;
1023*2882Svi117747  * abs-path       =  "/" path-segments
1024*2882Svi117747  * path-segments  =  segment *( "/" segment )
1025*2882Svi117747  * segment        =  *pchar *( ";" param )
1026*2882Svi117747  * param          =  *pchar
1027*2882Svi117747  * pchar          =  unreserved / escaped /
1028*2882Svi117747  *                   ":" / "@" / "&" / "=" / "+" / "$" / ","
1029*2882Svi117747  */
1030*2882Svi117747 static void
1031*2882Svi117747 sip_uri_parse_abs_path(_sip_uri_t *outurl, char *scan, char *uend)
1032*2882Svi117747 {
1033*2882Svi117747 	if (scan == uend || *scan != '/')
1034*2882Svi117747 		return;
1035*2882Svi117747 	outurl->sip_uri_path.sip_str_ptr = scan;
1036*2882Svi117747 	outurl->sip_uri_path.sip_str_len = uend - scan;
1037*2882Svi117747 
1038*2882Svi117747 	++scan;
1039*2882Svi117747 	while (scan < uend && (SIP_URI_ISPCHAR(*scan) ||
1040*2882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
1041*2882Svi117747 	    *scan == '/' || *scan == ';')) {
1042*2882Svi117747 		++scan;
1043*2882Svi117747 	}
1044*2882Svi117747 	if (scan < uend)
1045*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PATH;
1046*2882Svi117747 }
1047*2882Svi117747 /*
1048*2882Svi117747  * reg-name =  1*( unreserved / escaped / "$" / "," / ";"
1049*2882Svi117747  *             / ":" / "@" / "&" / "=" / "+" )
1050*2882Svi117747  */
1051*2882Svi117747 static void
1052*2882Svi117747 sip_uri_parse_abs_regname(_sip_uri_t *outurl, char *scan, char *uend)
1053*2882Svi117747 {
1054*2882Svi117747 	if (scan == uend)
1055*2882Svi117747 		return;
1056*2882Svi117747 	outurl->sip_uri_regname.sip_str_ptr = scan;
1057*2882Svi117747 	outurl->sip_uri_regname.sip_str_len = uend - scan;
1058*2882Svi117747 
1059*2882Svi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1060*2882Svi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISREGNAME(*scan))) {
1061*2882Svi117747 		++scan;
1062*2882Svi117747 	}
1063*2882Svi117747 	if (scan < uend)
1064*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_REGNAME;
1065*2882Svi117747 }
1066*2882Svi117747 
1067*2882Svi117747 /*
1068*2882Svi117747  * The format of the password is supposed to be :XXX
1069*2882Svi117747  * password =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
1070*2882Svi117747  */
1071*2882Svi117747 static void
1072*2882Svi117747 sip_uri_parse_password(_sip_uri_t *outurl, char *scan, char *uend)
1073*2882Svi117747 {
1074*2882Svi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend)
1075*2882Svi117747 		return;
1076*2882Svi117747 	++scan;
1077*2882Svi117747 	outurl->sip_uri_password.sip_str_ptr = scan;
1078*2882Svi117747 	outurl->sip_uri_password.sip_str_len = uend - scan;
1079*2882Svi117747 
1080*2882Svi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1081*2882Svi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISOTHER(*scan) ||
1082*2882Svi117747 	    *scan == '&')) {
1083*2882Svi117747 		++scan;
1084*2882Svi117747 	}
1085*2882Svi117747 	if (scan < uend)
1086*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PASS;
1087*2882Svi117747 }
1088*2882Svi117747 
1089*2882Svi117747 /*
1090*2882Svi117747  * user =  1*( unreserved / escaped / user-unreserved )
1091*2882Svi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
1092*2882Svi117747  */
1093*2882Svi117747 static void
1094*2882Svi117747 sip_uri_parse_user(_sip_uri_t *outurl, char *scan, char *uend)
1095*2882Svi117747 {
1096*2882Svi117747 	if (scan == uend) {
1097*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_USER;
1098*2882Svi117747 		return;
1099*2882Svi117747 	}
1100*2882Svi117747 	outurl->sip_uri_user.sip_str_ptr = scan;
1101*2882Svi117747 	outurl->sip_uri_user.sip_str_len = uend - scan;
1102*2882Svi117747 
1103*2882Svi117747 	if (sip_uri_parse_tel(scan, uend)) {
1104*2882Svi117747 		outurl->sip_uri_isteluser = B_TRUE;
1105*2882Svi117747 	} else {
1106*2882Svi117747 		while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1107*2882Svi117747 		    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISUSER(*scan))) {
1108*2882Svi117747 			++scan;
1109*2882Svi117747 		}
1110*2882Svi117747 		if (scan < uend)
1111*2882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_USER;
1112*2882Svi117747 	}
1113*2882Svi117747 }
1114*2882Svi117747 
1115*2882Svi117747 /*
1116*2882Svi117747  * the format of port is supposed to be :XXX
1117*2882Svi117747  * port =  1*DIGIT
1118*2882Svi117747  */
1119*2882Svi117747 static void
1120*2882Svi117747 sip_uri_parse_port(_sip_uri_t *outurl, char *scan, char *uend)
1121*2882Svi117747 {
1122*2882Svi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend) {
1123*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1124*2882Svi117747 		return;
1125*2882Svi117747 	}
1126*2882Svi117747 	++scan;
1127*2882Svi117747 	/*
1128*2882Svi117747 	 * parse numeric port number
1129*2882Svi117747 	 */
1130*2882Svi117747 	if (SIP_URI_ISDIGIT(*scan)) {
1131*2882Svi117747 		outurl->sip_uri_port = *scan - '0';
1132*2882Svi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1133*2882Svi117747 		    outurl->sip_uri_port =
1134*2882Svi117747 			outurl->sip_uri_port * 10 + (*scan - '0');
1135*2882Svi117747 			if (outurl->sip_uri_port > 0xffff) {
1136*2882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1137*2882Svi117747 				outurl->sip_uri_port = 0;
1138*2882Svi117747 				break;
1139*2882Svi117747 			}
1140*2882Svi117747 		}
1141*2882Svi117747 	}
1142*2882Svi117747 	if (scan < uend) {
1143*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1144*2882Svi117747 		outurl->sip_uri_port = 0;
1145*2882Svi117747 	}
1146*2882Svi117747 }
1147*2882Svi117747 
1148*2882Svi117747 /*
1149*2882Svi117747  * parse an IPv4 address
1150*2882Svi117747  *    1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1151*2882Svi117747  *  advances pscan to end of IPv4 address, or after last "." that was
1152*2882Svi117747  *  a valid IPv4 or domain name.
1153*2882Svi117747  * returns 1 if ipv4 found, 0 otherwise
1154*2882Svi117747  */
1155*2882Svi117747 static int
1156*2882Svi117747 sip_uri_parse_ipv4(char *scan, char *uend)
1157*2882Svi117747 {
1158*2882Svi117747 	int	j = 0;
1159*2882Svi117747 	int	val = 0;
1160*2882Svi117747 
1161*2882Svi117747 	for (j = 0; j < 4; ++j) {
1162*2882Svi117747 		if (!SIP_URI_ISDIGIT(*scan))
1163*2882Svi117747 			break;
1164*2882Svi117747 		val = *scan - '0';
1165*2882Svi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1166*2882Svi117747 			val = val * 10 + (*scan - '0');
1167*2882Svi117747 			if (val > 255)
1168*2882Svi117747 				return (0);
1169*2882Svi117747 		}
1170*2882Svi117747 		if (j < 3) {
1171*2882Svi117747 			if (*scan != '.')
1172*2882Svi117747 				break;
1173*2882Svi117747 			++scan;
1174*2882Svi117747 		}
1175*2882Svi117747 	}
1176*2882Svi117747 
1177*2882Svi117747 	if (j == 4 && scan == uend)
1178*2882Svi117747 		return (1);
1179*2882Svi117747 
1180*2882Svi117747 	return (0);
1181*2882Svi117747 }
1182*2882Svi117747 
1183*2882Svi117747 /*
1184*2882Svi117747  * parse an IPv6 address
1185*2882Svi117747  *  IPv6address = hexpart [ ":" IPv4address ]
1186*2882Svi117747  *  IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1187*2882Svi117747  *  hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
1188*2882Svi117747  *  hexseq  = hex4 *( ":" hex4)
1189*2882Svi117747  *  hex4    = 1*4HEXDIG
1190*2882Svi117747  *  if not found, leaves pscan unchanged, otherwise advances to end
1191*2882Svi117747  *  returns 1 if valid,
1192*2882Svi117747  *  0 if invalid
1193*2882Svi117747  */
1194*2882Svi117747 static int
1195*2882Svi117747 sip_uri_parse_ipv6(char *scan, char *uend)
1196*2882Svi117747 {
1197*2882Svi117747 	char		*mark;
1198*2882Svi117747 	unsigned	j = 0;			/* index for addr */
1199*2882Svi117747 	unsigned	val = 0;		/* hex value */
1200*2882Svi117747 	int		zpad = 0;		/* index of :: delimiter */
1201*2882Svi117747 
1202*2882Svi117747 	if (*scan != '[')
1203*2882Svi117747 		return (0);
1204*2882Svi117747 	++scan;
1205*2882Svi117747 	j = 0;
1206*2882Svi117747 
1207*2882Svi117747 	/*
1208*2882Svi117747 	 * check for leading "::", set zpad to the position of the "::"
1209*2882Svi117747 	 */
1210*2882Svi117747 	if (scan + 1 < uend && scan[0] == ':' && scan[1] == ':') {
1211*2882Svi117747 		zpad = 0;
1212*2882Svi117747 		scan += 2;
1213*2882Svi117747 	} else {
1214*2882Svi117747 		zpad = -1;
1215*2882Svi117747 	}
1216*2882Svi117747 
1217*2882Svi117747 	/*
1218*2882Svi117747 	 * loop through up to 16 bytes of IPv6 address
1219*2882Svi117747 	 */
1220*2882Svi117747 	while (scan < uend && j < 15) {
1221*2882Svi117747 		if (!SIP_URI_ISHEX(*scan))
1222*2882Svi117747 			break;
1223*2882Svi117747 		mark = scan;
1224*2882Svi117747 		val = SIP_URI_HEXVAL(*scan);
1225*2882Svi117747 		while (++scan < uend && SIP_URI_ISHEX(*scan)) {
1226*2882Svi117747 			val = val * 16 + SIP_URI_HEXVAL(*scan);
1227*2882Svi117747 			if (val > 0xffff)
1228*2882Svi117747 				return (0);
1229*2882Svi117747 		}
1230*2882Svi117747 
1231*2882Svi117747 		/*
1232*2882Svi117747 		 * always require a delimiter or ]
1233*2882Svi117747 		 */
1234*2882Svi117747 		if (scan == uend)
1235*2882Svi117747 			return (0);
1236*2882Svi117747 
1237*2882Svi117747 		if (*scan == '.' && (j == 12 || (zpad != -1 && j < 12)) &&
1238*2882Svi117747 		    mark < uend && sip_uri_parse_ipv4(mark, uend - 1) &&
1239*2882Svi117747 		    *(uend - 1) == ']') {
1240*2882Svi117747 			mark = uend - 1;
1241*2882Svi117747 			j += 4;
1242*2882Svi117747 			scan = mark + 1;
1243*2882Svi117747 			break;
1244*2882Svi117747 		}
1245*2882Svi117747 
1246*2882Svi117747 		/*
1247*2882Svi117747 		 * set address
1248*2882Svi117747 		 */
1249*2882Svi117747 		j += 2;
1250*2882Svi117747 
1251*2882Svi117747 		/*
1252*2882Svi117747 		 * check for delimiter or ]
1253*2882Svi117747 		 */
1254*2882Svi117747 		if (*scan == ':') {
1255*2882Svi117747 			/*
1256*2882Svi117747 			 * found ":" delimiter, check for "::"
1257*2882Svi117747 			 */
1258*2882Svi117747 			if (++scan < uend && *scan == ':') {
1259*2882Svi117747 				if (zpad != -1)
1260*2882Svi117747 					return (0);
1261*2882Svi117747 				zpad = j;
1262*2882Svi117747 				if (++scan < uend && *scan == ']') {
1263*2882Svi117747 					++scan;
1264*2882Svi117747 					break;
1265*2882Svi117747 				}
1266*2882Svi117747 			}
1267*2882Svi117747 		} else if (*scan == ']' && (j == 16 || zpad != -1)) {
1268*2882Svi117747 			++scan;
1269*2882Svi117747 			break;
1270*2882Svi117747 		} else {
1271*2882Svi117747 			/*
1272*2882Svi117747 			 * not a valid delimiter
1273*2882Svi117747 			 */
1274*2882Svi117747 			return (0);
1275*2882Svi117747 		}
1276*2882Svi117747 	}
1277*2882Svi117747 	if (zpad == -1 && j < 16)
1278*2882Svi117747 		return (0);
1279*2882Svi117747 	if (zpad != -1) {
1280*2882Svi117747 		if (j > 15)
1281*2882Svi117747 			return (0);
1282*2882Svi117747 	}
1283*2882Svi117747 
1284*2882Svi117747 	if (scan == uend)
1285*2882Svi117747 		return (1);
1286*2882Svi117747 
1287*2882Svi117747 	return (0);
1288*2882Svi117747 }
1289*2882Svi117747 
1290*2882Svi117747 /*
1291*2882Svi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
1292*2882Svi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
1293*2882Svi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
1294*2882Svi117747  */
1295*2882Svi117747 static int
1296*2882Svi117747 sip_uri_parse_hostname(char *scan, char *uend)
1297*2882Svi117747 {
1298*2882Svi117747 	int	sawalpha = 0;
1299*2882Svi117747 
1300*2882Svi117747 	if (scan < uend && SIP_URI_ISALNUM(*scan)) {
1301*2882Svi117747 		do {
1302*2882Svi117747 			sawalpha = SIP_URI_ISALPHA(*scan);
1303*2882Svi117747 			while (SIP_URI_ISHOST(*scan))
1304*2882Svi117747 				++scan;
1305*2882Svi117747 			if (*scan != '.')
1306*2882Svi117747 				break;
1307*2882Svi117747 			++scan;
1308*2882Svi117747 		} while (scan < uend && SIP_URI_ISALNUM(*scan));
1309*2882Svi117747 	}
1310*2882Svi117747 
1311*2882Svi117747 	if (sawalpha && scan == uend)
1312*2882Svi117747 		return (1);
1313*2882Svi117747 	return (0);
1314*2882Svi117747 }
1315*2882Svi117747 
1316*2882Svi117747 
1317*2882Svi117747 /*
1318*2882Svi117747  * parse the network path portion of a full URL
1319*2882Svi117747  */
1320*2882Svi117747 static void
1321*2882Svi117747 sip_uri_parse_netpath(_sip_uri_t *outurl, char **pscan, char *uend,
1322*2882Svi117747     boolean_t issip)
1323*2882Svi117747 {
1324*2882Svi117747 	char	*mark = (char *)0;
1325*2882Svi117747 	char	*mark2 = (char *)0;
1326*2882Svi117747 	char	*scan = *pscan;
1327*2882Svi117747 	int	gothost = 0;
1328*2882Svi117747 
1329*2882Svi117747 	/*
1330*2882Svi117747 	 * look for the first high-level delimiter
1331*2882Svi117747 	 */
1332*2882Svi117747 	mark = scan;
1333*2882Svi117747 	while (scan < uend && *scan != '@')
1334*2882Svi117747 		++scan;
1335*2882Svi117747 	/*
1336*2882Svi117747 	 * handle userinfo section of URL
1337*2882Svi117747 	 */
1338*2882Svi117747 	if (scan < uend && *scan == '@') {
1339*2882Svi117747 		/*
1340*2882Svi117747 		 * parse user
1341*2882Svi117747 		 */
1342*2882Svi117747 		mark2 = mark;
1343*2882Svi117747 		while (mark < scan && *mark != ':')
1344*2882Svi117747 			++mark;
1345*2882Svi117747 		sip_uri_parse_user(outurl, mark2, mark);
1346*2882Svi117747 		/*
1347*2882Svi117747 		 * parse password
1348*2882Svi117747 		 */
1349*2882Svi117747 		if (*mark == ':')
1350*2882Svi117747 			sip_uri_parse_password(outurl, mark, scan);
1351*2882Svi117747 		mark = ++scan;
1352*2882Svi117747 	}
1353*2882Svi117747 
1354*2882Svi117747 	scan = mark;
1355*2882Svi117747 	if (scan < uend && *scan == '[') {	/* look for an IPv6 address */
1356*2882Svi117747 		while (scan < uend && *scan != ']')
1357*2882Svi117747 			++scan;
1358*2882Svi117747 		if (scan < uend) {
1359*2882Svi117747 			++scan;
1360*2882Svi117747 			if (sip_uri_parse_ipv6(mark, scan))
1361*2882Svi117747 				gothost = 1;
1362*2882Svi117747 		}
1363*2882Svi117747 	} else {
1364*2882Svi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPHDELIM(*scan)) ||
1365*2882Svi117747 		    (!issip && !SIP_URI_ISABSHDELIM(*scan)))) {
1366*2882Svi117747 			++scan;
1367*2882Svi117747 		}
1368*2882Svi117747 
1369*2882Svi117747 		/*
1370*2882Svi117747 		 * look for an IPv4 address
1371*2882Svi117747 		 */
1372*2882Svi117747 		if (mark < scan && SIP_URI_ISDIGIT(*mark) &&
1373*2882Svi117747 		    sip_uri_parse_ipv4(mark, scan)) {
1374*2882Svi117747 			gothost = 1;
1375*2882Svi117747 		}
1376*2882Svi117747 
1377*2882Svi117747 		/*
1378*2882Svi117747 		 * look for a valid host name
1379*2882Svi117747 		 */
1380*2882Svi117747 		if (!gothost && mark < scan &&
1381*2882Svi117747 		    sip_uri_parse_hostname(mark, scan)) {
1382*2882Svi117747 			gothost = 1;
1383*2882Svi117747 		}
1384*2882Svi117747 	}
1385*2882Svi117747 	/*
1386*2882Svi117747 	 * handle invalid host name
1387*2882Svi117747 	 */
1388*2882Svi117747 	if (!gothost)
1389*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HOST;
1390*2882Svi117747 	/*
1391*2882Svi117747 	 * save host name
1392*2882Svi117747 	 */
1393*2882Svi117747 	outurl->sip_uri_host.sip_str_ptr = mark;
1394*2882Svi117747 	outurl->sip_uri_host.sip_str_len = scan - mark;
1395*2882Svi117747 
1396*2882Svi117747 	mark = scan;
1397*2882Svi117747 	/*
1398*2882Svi117747 	 * parse the port number
1399*2882Svi117747 	 */
1400*2882Svi117747 	if (scan < uend && *scan == ':') {
1401*2882Svi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPDELIM(*scan)) ||
1402*2882Svi117747 		    (!issip && !SIP_URI_ISABSDELIM(*scan)))) {
1403*2882Svi117747 			++scan;
1404*2882Svi117747 		}
1405*2882Svi117747 		sip_uri_parse_port(outurl, mark, scan);
1406*2882Svi117747 	}
1407*2882Svi117747 
1408*2882Svi117747 	/*
1409*2882Svi117747 	 * set return pointer
1410*2882Svi117747 	 */
1411*2882Svi117747 	*pscan = scan;
1412*2882Svi117747 }
1413*2882Svi117747 
1414*2882Svi117747 /*
1415*2882Svi117747  * parse a URL
1416*2882Svi117747  * URL = SIP-URI / SIPS-URI / absoluteURI
1417*2882Svi117747  */
1418*2882Svi117747 void
1419*2882Svi117747 sip_uri_parse_it(_sip_uri_t *outurl, sip_str_t *uri_str)
1420*2882Svi117747 {
1421*2882Svi117747 	char 		*mark;
1422*2882Svi117747 	char		*scan;
1423*2882Svi117747 	char		*uend;
1424*2882Svi117747 	char		*str = uri_str->sip_str_ptr;
1425*2882Svi117747 	unsigned	urlen = uri_str->sip_str_len;
1426*2882Svi117747 
1427*2882Svi117747 	/*
1428*2882Svi117747 	 * reset output parameters
1429*2882Svi117747 	 */
1430*2882Svi117747 	(void) memset(outurl, 0, sizeof (sip_uri_t));
1431*2882Svi117747 
1432*2882Svi117747 	/*
1433*2882Svi117747 	 * strip enclosing angle brackets
1434*2882Svi117747 	 */
1435*2882Svi117747 	if (urlen > 1 && str[0] == '<' && str[urlen-1] == '>') {
1436*2882Svi117747 		urlen -= 2;
1437*2882Svi117747 		++str;
1438*2882Svi117747 	}
1439*2882Svi117747 	uend = str + urlen;
1440*2882Svi117747 
1441*2882Svi117747 	/*
1442*2882Svi117747 	 * strip off space prefix and trailing spaces
1443*2882Svi117747 	 */
1444*2882Svi117747 	while (str < uend && isspace(*str)) {
1445*2882Svi117747 		++str;
1446*2882Svi117747 		--urlen;
1447*2882Svi117747 	}
1448*2882Svi117747 	while (str < uend && isspace(*(uend - 1))) {
1449*2882Svi117747 		--uend;
1450*2882Svi117747 		--urlen;
1451*2882Svi117747 	}
1452*2882Svi117747 
1453*2882Svi117747 	/*
1454*2882Svi117747 	 * strip off "URL:" prefix
1455*2882Svi117747 	 */
1456*2882Svi117747 	if (urlen > 4 && sip_uri_url_casecmp(str, "URL:", 4) == 0) {
1457*2882Svi117747 		str += 4;
1458*2882Svi117747 		urlen -= 4;
1459*2882Svi117747 	}
1460*2882Svi117747 
1461*2882Svi117747 	/*
1462*2882Svi117747 	 * parse the scheme name
1463*2882Svi117747 	 */
1464*2882Svi117747 	mark = scan = str;
1465*2882Svi117747 	while (scan < uend && *scan != ':')
1466*2882Svi117747 		++scan;
1467*2882Svi117747 	if (scan == uend || !sip_uri_parse_scheme(outurl, mark, scan)) {
1468*2882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
1469*2882Svi117747 		return;
1470*2882Svi117747 	}
1471*2882Svi117747 
1472*2882Svi117747 	if ((outurl->sip_uri_scheme.sip_str_len == SIP_SCHEME_LEN &&
1473*2882Svi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIP_SCHEME,
1474*2882Svi117747 	    SIP_SCHEME_LEN)) ||
1475*2882Svi117747 	    (outurl->sip_uri_scheme.sip_str_len == SIPS_SCHEME_LEN &&
1476*2882Svi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIPS_SCHEME,
1477*2882Svi117747 	    SIPS_SCHEME_LEN))) {
1478*2882Svi117747 		outurl->sip_uri_issip = B_TRUE;
1479*2882Svi117747 	} else {
1480*2882Svi117747 		outurl->sip_uri_issip = B_FALSE;
1481*2882Svi117747 	}
1482*2882Svi117747 	++scan; /* skip ':' */
1483*2882Svi117747 
1484*2882Svi117747 	if (outurl->sip_uri_issip) {
1485*2882Svi117747 		/*
1486*2882Svi117747 		 * parse SIP URL
1487*2882Svi117747 		 */
1488*2882Svi117747 		sip_uri_parse_netpath(outurl, &scan, uend, B_TRUE);
1489*2882Svi117747 
1490*2882Svi117747 		/*
1491*2882Svi117747 		 * parse parameters
1492*2882Svi117747 		 */
1493*2882Svi117747 		if (scan < uend && *scan == ';') {
1494*2882Svi117747 			mark = scan;
1495*2882Svi117747 			while (scan < uend && *scan != '?')
1496*2882Svi117747 				++scan;
1497*2882Svi117747 			sip_uri_parse_params(outurl, mark, scan);
1498*2882Svi117747 		}
1499*2882Svi117747 
1500*2882Svi117747 		/*
1501*2882Svi117747 		 * parse headers
1502*2882Svi117747 		 */
1503*2882Svi117747 		if (scan < uend && *scan == '?')
1504*2882Svi117747 			sip_uri_parse_headers(outurl, scan, uend);
1505*2882Svi117747 	} else if (scan < uend && scan[0] == '/') {	 /* parse absoluteURL */
1506*2882Svi117747 		++scan;
1507*2882Svi117747 		/*
1508*2882Svi117747 		 * parse authority
1509*2882Svi117747 		 * authority	= srvr / reg-name
1510*2882Svi117747 		 * srvr		= [ [ userinfo "@" ] hostport ]
1511*2882Svi117747 		 * reg-name	= 1*(unreserved / escaped / "$" / ","
1512*2882Svi117747 		 *			/ ";" / ":" / "@" / "&" / "=" / "+")
1513*2882Svi117747 		 */
1514*2882Svi117747 		if (scan < uend && *scan == '/') {
1515*2882Svi117747 			++scan;
1516*2882Svi117747 			mark = scan;
1517*2882Svi117747 			/*
1518*2882Svi117747 			 * take authority as srvr
1519*2882Svi117747 			 */
1520*2882Svi117747 			sip_uri_parse_netpath(outurl, &scan, uend, B_FALSE);
1521*2882Svi117747 
1522*2882Svi117747 			/*
1523*2882Svi117747 			 * if srvr failed, take it as reg-name
1524*2882Svi117747 			 * parse reg-name
1525*2882Svi117747 			 */
1526*2882Svi117747 			if (outurl->sip_uri_errflags & SIP_URIERR_USER ||
1527*2882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PASS ||
1528*2882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_HOST ||
1529*2882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PORT) {
1530*2882Svi117747 				scan = mark;
1531*2882Svi117747 				while (scan < uend && *scan != '/' &&
1532*2882Svi117747 					*scan != '?') {
1533*2882Svi117747 					++scan;
1534*2882Svi117747 				}
1535*2882Svi117747 				sip_uri_parse_abs_regname(outurl, mark, scan);
1536*2882Svi117747 				if (!(outurl->sip_uri_errflags &
1537*2882Svi117747 				    SIP_URIERR_REGNAME)) {
1538*2882Svi117747 					/*
1539*2882Svi117747 					 * remove error info of user,
1540*2882Svi117747 					 * password, host, port
1541*2882Svi117747 					 */
1542*2882Svi117747 					outurl->sip_uri_user.sip_str_ptr = NULL;
1543*2882Svi117747 					outurl->sip_uri_user.sip_str_len = 0;
1544*2882Svi117747 					outurl->sip_uri_errflags &=
1545*2882Svi117747 					    ~SIP_URIERR_USER;
1546*2882Svi117747 					outurl->sip_uri_password.sip_str_ptr =
1547*2882Svi117747 					    NULL;
1548*2882Svi117747 					outurl->sip_uri_password.sip_str_len =
1549*2882Svi117747 					    0;
1550*2882Svi117747 					outurl->sip_uri_errflags &=
1551*2882Svi117747 					    ~SIP_URIERR_PASS;
1552*2882Svi117747 					outurl->sip_uri_host.sip_str_ptr = NULL;
1553*2882Svi117747 					outurl->sip_uri_host.sip_str_len = 0;
1554*2882Svi117747 					outurl->sip_uri_errflags &=
1555*2882Svi117747 					    ~SIP_URIERR_HOST;
1556*2882Svi117747 					outurl->sip_uri_port = 0;
1557*2882Svi117747 					outurl->sip_uri_errflags &=
1558*2882Svi117747 					    ~SIP_URIERR_PORT;
1559*2882Svi117747 				}
1560*2882Svi117747 			}
1561*2882Svi117747 		} else {
1562*2882Svi117747 			/*
1563*2882Svi117747 			 * there is no net-path
1564*2882Svi117747 			 */
1565*2882Svi117747 			--scan;
1566*2882Svi117747 		}
1567*2882Svi117747 		/*
1568*2882Svi117747 		 * parse abs-path
1569*2882Svi117747 		 */
1570*2882Svi117747 		if (scan < uend && *scan == '/') {
1571*2882Svi117747 			mark = scan;
1572*2882Svi117747 			while (scan < uend && *scan != '?')
1573*2882Svi117747 				++scan;
1574*2882Svi117747 			sip_uri_parse_abs_path(outurl, mark, scan);
1575*2882Svi117747 		}
1576*2882Svi117747 
1577*2882Svi117747 		/*
1578*2882Svi117747 		 * parse query
1579*2882Svi117747 		 */
1580*2882Svi117747 		if (scan < uend && *scan == '?')
1581*2882Svi117747 			sip_uri_parse_abs_query(outurl, scan, uend);
1582*2882Svi117747 	} else {
1583*2882Svi117747 		/*
1584*2882Svi117747 		 * parse opaque-part
1585*2882Svi117747 		 */
1586*2882Svi117747 		sip_uri_parse_abs_opaque(outurl, scan, uend);
1587*2882Svi117747 	}
1588*2882Svi117747 }
1589