xref: /titanic_51/usr/src/lib/libsip/common/sip_parse_uri.c (revision 2c2c41837e330b002c4220a39638150db504fe0e)
140cb5e5dSvi117747 /*
240cb5e5dSvi117747  * CDDL HEADER START
340cb5e5dSvi117747  *
440cb5e5dSvi117747  * The contents of this file are subject to the terms of the
540cb5e5dSvi117747  * Common Development and Distribution License (the "License").
640cb5e5dSvi117747  * You may not use this file except in compliance with the License.
740cb5e5dSvi117747  *
840cb5e5dSvi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi117747  * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi117747  * See the License for the specific language governing permissions
1140cb5e5dSvi117747  * and limitations under the License.
1240cb5e5dSvi117747  *
1340cb5e5dSvi117747  * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi117747  * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi117747  * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi117747  *
1940cb5e5dSvi117747  * CDDL HEADER END
2040cb5e5dSvi117747  */
2140cb5e5dSvi117747 
2240cb5e5dSvi117747 /*
23*2c2c4183Svi117747  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi117747  * Use is subject to license terms.
2540cb5e5dSvi117747  */
2640cb5e5dSvi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2740cb5e5dSvi117747 
28*2c2c4183Svi117747 #include <ctype.h>
2940cb5e5dSvi117747 #include <stdlib.h>
3040cb5e5dSvi117747 #include <string.h>
3140cb5e5dSvi117747 
3240cb5e5dSvi117747 #include "sip_parse_uri.h"
3340cb5e5dSvi117747 
3440cb5e5dSvi117747 /*
3540cb5e5dSvi117747  * SIP-URI          =  "sip:" [ userinfo ] hostport uri-parameters [ headers ]
3640cb5e5dSvi117747  * SIPS-URI         =  "sips:" [ userinfo ] hostport uri-parameters [ headers ]
3740cb5e5dSvi117747  * userinfo         =  ( user / telephone-subscriber ) [ ":" password ] "@"
3840cb5e5dSvi117747  * user             =  1*( unreserved / escaped / user-unreserved )
3940cb5e5dSvi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
4040cb5e5dSvi117747  * password         =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
4140cb5e5dSvi117747  * hostport         =  host [ ":" port ]
4240cb5e5dSvi117747  * host             =  hostname / IPv4address / IPv6reference
4340cb5e5dSvi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
4440cb5e5dSvi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
4540cb5e5dSvi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
4640cb5e5dSvi117747  * IPv4address    =  1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
4740cb5e5dSvi117747  * IPv6reference  =  "[" IPv6address "]"
4840cb5e5dSvi117747  * IPv6address    =  hexpart [ ":" IPv4address ]
4940cb5e5dSvi117747  * hexpart        =  hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
5040cb5e5dSvi117747  * hexseq         =  hex4 *( ":" hex4)
5140cb5e5dSvi117747  * hex4           =  1*4HEXDIG
5240cb5e5dSvi117747  * port           =  1*DIGIT
5340cb5e5dSvi117747  *
5440cb5e5dSvi117747  * The BNF for telephone-subscriber can be found in RFC 2806 [9].  Note,
5540cb5e5dSvi117747  * however, that any characters allowed there that are not allowed in
5640cb5e5dSvi117747  * the user part of the SIP URI MUST be escaped.
5740cb5e5dSvi117747  *
5840cb5e5dSvi117747  * uri-parameters    =  *( ";" uri-parameter)
5940cb5e5dSvi117747  * uri-parameter     =  transport-param / user-param / method-param
6040cb5e5dSvi117747  *                      / ttl-param / maddr-param / lr-param / other-param
6140cb5e5dSvi117747  * transport-param   =  "transport="( "udp" / "tcp" / "sctp" / "tls"
6240cb5e5dSvi117747  *                     / other-transport)
6340cb5e5dSvi117747  * other-transport   =  token
6440cb5e5dSvi117747  * user-param        =  "user=" ( "phone" / "ip" / other-user)
6540cb5e5dSvi117747  * other-user        =  token
6640cb5e5dSvi117747  * method-param      =  "method=" Method
6740cb5e5dSvi117747  * ttl-param         =  "ttl=" ttl
6840cb5e5dSvi117747  * maddr-param       =  "maddr=" host
6940cb5e5dSvi117747  * lr-param          =  "lr"
7040cb5e5dSvi117747  * other-param       =  pname [ "=" pvalue ]
7140cb5e5dSvi117747  * pname             =  1*paramchar
7240cb5e5dSvi117747  * pvalue            =  1*paramchar
7340cb5e5dSvi117747  * paramchar         =  param-unreserved / unreserved / escaped
7440cb5e5dSvi117747  * param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
7540cb5e5dSvi117747  * headers         =  "?" header *( "&" header )
7640cb5e5dSvi117747  * header          =  hname "=" hvalue
7740cb5e5dSvi117747  * hname           =  1*( hnv-unreserved / unreserved / escaped )
7840cb5e5dSvi117747  * hvalue          =  *( hnv-unreserved / unreserved / escaped )
7940cb5e5dSvi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
8040cb5e5dSvi117747  *
8140cb5e5dSvi117747  */
8240cb5e5dSvi117747 
8340cb5e5dSvi117747 #define	SIP_URI_MSG_BUF_SZ	100
8440cb5e5dSvi117747 
8540cb5e5dSvi117747 #define	SIP_URI_ISHEX(c)					\
8640cb5e5dSvi117747 	(((int)(c) >= 0x30 && (int)(c) <= 0x39) || 	\
8740cb5e5dSvi117747 	((int)(c) >= 0x41 && (int)(c) <= 0x46) || 	\
8840cb5e5dSvi117747 	((int)(c) >= 0x61 && (int)(c) <= 0x66))
8940cb5e5dSvi117747 
9040cb5e5dSvi117747 #define	SIP_URI_ISURLESCAPE(scan, end)			\
9140cb5e5dSvi117747 	((scan) + 2 < (end) && (scan)[0] == '%' && 	\
9240cb5e5dSvi117747 	SIP_URI_ISHEX((scan)[1]) && SIP_URI_ISHEX((scan[2])))
9340cb5e5dSvi117747 
9440cb5e5dSvi117747 /*
9540cb5e5dSvi117747  * URL character classes
9640cb5e5dSvi117747  *  mark	- _ . ! ~ * ' ()
9740cb5e5dSvi117747  *  reserved	; / ? : @ & = + $ ,    also [] for IPv6
9840cb5e5dSvi117747  *  unreserved	alphanum mark
9940cb5e5dSvi117747  *  pchar	: @ & = + $ , unreserved
10040cb5e5dSvi117747  *  userinfo	; : & = + $ , unreserved escaped
10140cb5e5dSvi117747  *  relsegment	; @ & = + $ , unreserved escaped
10240cb5e5dSvi117747  *  reg_name	; : @ & = + $ , unreserved escaped
10340cb5e5dSvi117747  *  token	- _ . ! ~ * ' %  + `
10440cb5e5dSvi117747  *  param-unreserved  [ ] / : + $ &
10540cb5e5dSvi117747  *  hnv-unreserved    [ ] / : + $ ?
10640cb5e5dSvi117747  */
10740cb5e5dSvi117747 #define	SIP_URI_ALPHA_BIT		0x0001
10840cb5e5dSvi117747 #define	SIP_URI_DIGIT_BIT		0x0002
10940cb5e5dSvi117747 #define	SIP_URI_ALNUM_BITS		0x0003
11040cb5e5dSvi117747 #define	SIP_URI_SCHEME_BIT		0x0004	/* for - + . */
11140cb5e5dSvi117747 #define	SIP_URI_TOKEN_BIT		0x0008	/* for - _ . ! ~ * ' % + ` */
11240cb5e5dSvi117747 #define	SIP_URI_QUEST_BIT		0x0010	/* for ? */
11340cb5e5dSvi117747 #define	SIP_URI_AT_BIT			0x0020	/* for @ */
11440cb5e5dSvi117747 #define	SIP_URI_COLON_BIT		0x0040	/* for : */
11540cb5e5dSvi117747 #define	SIP_URI_SEMI_BIT		0x0080	/* for ; */
11640cb5e5dSvi117747 #define	SIP_URI_DASH_BIT		0x0100	/* for - */
11740cb5e5dSvi117747 #define	SIP_URI_MARK_BIT		0x0200	/* for - _ . ! ~ * ' ( ) */
11840cb5e5dSvi117747 #define	SIP_URI_AND_BIT			0x0400	/* for & */
11940cb5e5dSvi117747 #define	SIP_URI_PHCOMM_BIT		0x0800	/* for [ ] / : + $ */
12040cb5e5dSvi117747 #define	SIP_URI_OTHER_BIT		0x1000	/* for = + $ , */
12140cb5e5dSvi117747 #define	SIP_URI_SLASH_BIT		0x2000	/* for / */
12240cb5e5dSvi117747 #define	SIP_URI_VISUALSEP_BIT		0x4000	/* for -.() */
12340cb5e5dSvi117747 #define	SIP_URI_DTMFURI_DIGIT_BIT	0x8000	/* for *ABCD */
12440cb5e5dSvi117747 
12540cb5e5dSvi117747 #define	a 			SIP_URI_ALPHA_BIT
12640cb5e5dSvi117747 #define	d 			SIP_URI_DIGIT_BIT
12740cb5e5dSvi117747 #define	s 			SIP_URI_SCHEME_BIT
12840cb5e5dSvi117747 #define	t 			SIP_URI_TOKEN_BIT
12940cb5e5dSvi117747 #define	q 			SIP_URI_QUEST_BIT
13040cb5e5dSvi117747 #define	m 			SIP_URI_AT_BIT
13140cb5e5dSvi117747 #define	c 			SIP_URI_COLON_BIT
13240cb5e5dSvi117747 #define	i 			SIP_URI_SEMI_BIT
13340cb5e5dSvi117747 #define	h 			SIP_URI_DASH_BIT
13440cb5e5dSvi117747 #define	k 			SIP_URI_MARK_BIT
13540cb5e5dSvi117747 #define	n 			SIP_URI_AND_BIT
13640cb5e5dSvi117747 #define	o 			SIP_URI_PHCOMM_BIT
13740cb5e5dSvi117747 #define	r 			SIP_URI_OTHER_BIT
13840cb5e5dSvi117747 #define	l 			SIP_URI_SLASH_BIT
13940cb5e5dSvi117747 #define	v 			SIP_URI_VISUALSEP_BIT
14040cb5e5dSvi117747 #define	f 			SIP_URI_DTMFURI_DIGIT_BIT
14140cb5e5dSvi117747 
14240cb5e5dSvi117747 static const unsigned short sip_uri_table[256] = {
14340cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
14440cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
14540cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
14640cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
14740cb5e5dSvi117747 	0,	t|k,	0,	0,	o|r,	t,	n,	t|k,
14840cb5e5dSvi117747 	k|v,	k|v,	t|k|f, s|t|r|o,	r,  h|s|t|k|v, s|t|k|v,	o|l,
14940cb5e5dSvi117747 	d,	d,	d,	d,	d,	d,	d,	d,
15040cb5e5dSvi117747 	d,	d,	c|o,	i,	0,	r,	0,	q,
15140cb5e5dSvi117747 	m,	a|f,	a|f,	a|f,	a|f,	a,	a,	a,
15240cb5e5dSvi117747 	a,	a,	a,	a,	a,	a,	a,	a,
15340cb5e5dSvi117747 	a,	a,	a,	a,	a,	a,	a,	a,
15440cb5e5dSvi117747 	a,	a,	a,	o,	0,	o,	0,	t|k,
15540cb5e5dSvi117747 	t,	a,	a,	a,	a,	a,	a,	a,
15640cb5e5dSvi117747 	a,	a,	a,	a,	a,	a,	a,	a,
15740cb5e5dSvi117747 	a,	a,	a,	a,	a,	a,	a,	a,
15840cb5e5dSvi117747 	a,	a,	a,	0,	0,	0,	t|k,	0,
15940cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16040cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16140cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16240cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16340cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16440cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16540cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16640cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16740cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16840cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
16940cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17040cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17140cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17240cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17340cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17440cb5e5dSvi117747 	0,	0,	0,	0,	0,	0,	0,	0,
17540cb5e5dSvi117747 };
17640cb5e5dSvi117747 
17740cb5e5dSvi117747 #undef	a
17840cb5e5dSvi117747 #undef	d
17940cb5e5dSvi117747 #undef	s
18040cb5e5dSvi117747 #undef	t
18140cb5e5dSvi117747 #undef	q
18240cb5e5dSvi117747 #undef	m
18340cb5e5dSvi117747 #undef	c
18440cb5e5dSvi117747 #undef	i
18540cb5e5dSvi117747 #undef	h
18640cb5e5dSvi117747 #undef	k
18740cb5e5dSvi117747 #undef	n
18840cb5e5dSvi117747 #undef	o
18940cb5e5dSvi117747 #undef	r
19040cb5e5dSvi117747 #undef	l
19140cb5e5dSvi117747 #undef	v
19240cb5e5dSvi117747 #undef	f
19340cb5e5dSvi117747 
19440cb5e5dSvi117747 #define	SIP_URI_UT(c)			sip_uri_table[(unsigned char)(c)]
19540cb5e5dSvi117747 #define	SIP_URI_ISALPHA(c)		(SIP_URI_UT(c) & SIP_URI_ALPHA_BIT)
19640cb5e5dSvi117747 #define	SIP_URI_ISDIGIT(c)		(SIP_URI_UT(c) & SIP_URI_DIGIT_BIT)
19740cb5e5dSvi117747 #define	SIP_URI_ISALNUM(c)		(SIP_URI_UT(c) & SIP_URI_ALNUM_BITS)
19840cb5e5dSvi117747 #define	SIP_URI_ISSCHEME(c)		\
19940cb5e5dSvi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_SCHEME_BIT))
20040cb5e5dSvi117747 #define	SIP_URI_ISTOKEN(c)		\
20140cb5e5dSvi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_TOKEN_BIT))
20240cb5e5dSvi117747 #define	SIP_URI_ISSIPDELIM(c)		\
20340cb5e5dSvi117747 		(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
20440cb5e5dSvi117747 #define	SIP_URI_ISSIPHDELIM(c)					\
20540cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
20640cb5e5dSvi117747 #define	SIP_URI_ISHOST(c)		\
20740cb5e5dSvi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_DASH_BIT))
20840cb5e5dSvi117747 #define	SIP_URI_ISUSER(c)						\
20940cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|		\
21040cb5e5dSvi117747 	SIP_URI_QUEST_BIT|SIP_URI_SLASH_BIT|SIP_URI_AND_BIT))
21140cb5e5dSvi117747 
21240cb5e5dSvi117747 #define	SIP_URI_ISABSHDELIM(c)					\
21340cb5e5dSvi117747 	(SIP_URI_UT(c) & \
21440cb5e5dSvi117747 	(SIP_URI_SLASH_BIT|SIP_URI_COLON_BIT|SIP_URI_QUEST_BIT))
21540cb5e5dSvi117747 #define	SIP_URI_ISABSDELIM(c)	\
21640cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_SLASH_BIT|SIP_URI_QUEST_BIT))
21740cb5e5dSvi117747 #define	SIP_URI_ISUNRESERVED(c)	\
21840cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
21940cb5e5dSvi117747 #define	SIP_URI_ISPARAM(c)						\
22040cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_AND_BIT|\
22140cb5e5dSvi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
22240cb5e5dSvi117747 #define	SIP_URI_ISHEADER(c)						\
22340cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_QUEST_BIT|\
22440cb5e5dSvi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
22540cb5e5dSvi117747 #define	SIP_URI_ISOTHER(c)		(SIP_URI_UT(c) & SIP_URI_OTHER_BIT)
22640cb5e5dSvi117747 #define	SIP_URI_ISRESERVED(c)					\
22740cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_SLASH_BIT|	\
22840cb5e5dSvi117747 	SIP_URI_QUEST_BIT| SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
22940cb5e5dSvi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
23040cb5e5dSvi117747 #define	SIP_URI_ISPCHAR(c)	\
23140cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
23240cb5e5dSvi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
23340cb5e5dSvi117747 #define	SIP_URI_ISREGNAME(c)					\
23440cb5e5dSvi117747 	(SIP_URI_UT(c) & 	\
23540cb5e5dSvi117747 	(SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|SIP_URI_COLON_BIT|	\
23640cb5e5dSvi117747 	SIP_URI_AT_BIT|SIP_URI_AND_BIT))
23740cb5e5dSvi117747 #define	SIP_URI_ISPHONEDIGIT(c)	\
23840cb5e5dSvi117747 	(SIP_URI_UT(c) & (SIP_URI_DIGIT_BIT|SIP_URI_VISUALSEP_BIT))
23940cb5e5dSvi117747 #define	SIP_URI_ISDTMFDIGIT(c)	(SIP_URI_UT(c) & SIP_URI_DTMFURI_DIGIT_BIT)
24040cb5e5dSvi117747 
24140cb5e5dSvi117747 static int  sip_uri_url_casecmp(const char *, const char *, unsigned);
24240cb5e5dSvi117747 static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
24340cb5e5dSvi117747 static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
24440cb5e5dSvi117747 static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
24540cb5e5dSvi117747 static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
24640cb5e5dSvi117747 static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
24740cb5e5dSvi117747 static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
24840cb5e5dSvi117747 static int  sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
24940cb5e5dSvi117747 static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
25040cb5e5dSvi117747 static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
25140cb5e5dSvi117747 static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
25240cb5e5dSvi117747 static void sip_uri_parse_netpath(_sip_uri_t *, char **, char *, boolean_t);
25340cb5e5dSvi117747 static int  sip_uri_parse_ipv6(char *, char *);
25440cb5e5dSvi117747 static int  sip_uri_parse_ipv4(char *, char *);
25540cb5e5dSvi117747 static int  sip_uri_parse_hostname(char *, char *);
25640cb5e5dSvi117747 static int sip_uri_parse_tel(char *, char *);
25740cb5e5dSvi117747 static int sip_uri_parse_tel_areaspe(char *, char *);
25840cb5e5dSvi117747 static int sip_uri_parse_tel_servicepro(char *, char *);
25940cb5e5dSvi117747 static int sip_uri_parse_tel_futureext(char *, char *);
26040cb5e5dSvi117747 static int sip_uri_isTokenchar(char **, char *);
26140cb5e5dSvi117747 static int sip_uri_isEscapedPound(char **, char *);
26240cb5e5dSvi117747 static int sip_uri_hexVal(char *, char *);
26340cb5e5dSvi117747 static int SIP_URI_HEXVAL(int);
26440cb5e5dSvi117747 
26540cb5e5dSvi117747 /*
26640cb5e5dSvi117747  * get the hex value of a char
26740cb5e5dSvi117747  */
26840cb5e5dSvi117747 static int
26940cb5e5dSvi117747 SIP_URI_HEXVAL(int c)
27040cb5e5dSvi117747 {
27140cb5e5dSvi117747 	if (c >= 0x30 && c <= 0x39)
27240cb5e5dSvi117747 		return (c - '0');
27340cb5e5dSvi117747 	if (c >= 0x41 && c <= 0x46)
27440cb5e5dSvi117747 		return (c - 'A' + 10);
27540cb5e5dSvi117747 	if (c >= 0x61 && c <= 0x66)
27640cb5e5dSvi117747 		return (c - 'a' + 10);
27740cb5e5dSvi117747 	return (c);
27840cb5e5dSvi117747 }
27940cb5e5dSvi117747 
28040cb5e5dSvi117747 /*
28140cb5e5dSvi117747  * basic ASCII case-insensitive comparison
28240cb5e5dSvi117747  */
28340cb5e5dSvi117747 static int
28440cb5e5dSvi117747 sip_uri_url_casecmp(const char *str1, const char *str2, unsigned len)
28540cb5e5dSvi117747 {
28640cb5e5dSvi117747 	unsigned	j;
28740cb5e5dSvi117747 
28840cb5e5dSvi117747 	for (j = 0; j < len && tolower(str1[j]) == tolower(str2[j]) &&
28940cb5e5dSvi117747 	    str1[j] != '\0'; ++j) {
29040cb5e5dSvi117747 		;
29140cb5e5dSvi117747 	}
29240cb5e5dSvi117747 	return (j == len ? 0 : tolower(str2[j]) - tolower(str1[j]));
29340cb5e5dSvi117747 }
29440cb5e5dSvi117747 
29540cb5e5dSvi117747 /*
29640cb5e5dSvi117747  * telephone-subscriber  = global-phone-number / local-phone-number
29740cb5e5dSvi117747  * Please refer to RFC 2806
29840cb5e5dSvi117747  */
29940cb5e5dSvi117747 static int
30040cb5e5dSvi117747 sip_uri_parse_tel(char *scan, char *uend)
30140cb5e5dSvi117747 {
30240cb5e5dSvi117747 	char	*mark = (char *)0;
30340cb5e5dSvi117747 	int	ret = 0;
30440cb5e5dSvi117747 	int	isGlobal = 0;
30540cb5e5dSvi117747 	int	quote = 0;
30640cb5e5dSvi117747 
30740cb5e5dSvi117747 	if (scan == uend)
30840cb5e5dSvi117747 		return (0);
30940cb5e5dSvi117747 	if (*scan == '+') {
31040cb5e5dSvi117747 		++scan;
31140cb5e5dSvi117747 		isGlobal = 1;
31240cb5e5dSvi117747 	}
31340cb5e5dSvi117747 	mark = scan;
31440cb5e5dSvi117747 	if (isGlobal) {
31540cb5e5dSvi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
31640cb5e5dSvi117747 			++scan;
31740cb5e5dSvi117747 	} else {
31840cb5e5dSvi117747 		while (scan < uend &&
31940cb5e5dSvi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
32040cb5e5dSvi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
32140cb5e5dSvi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
32240cb5e5dSvi117747 		    *scan == 'p' || *scan == 'w')) {
32340cb5e5dSvi117747 			++scan;
32440cb5e5dSvi117747 		}
32540cb5e5dSvi117747 	}
32640cb5e5dSvi117747 	if (mark == scan || (scan < uend && *scan != ';'))
32740cb5e5dSvi117747 		return (0);
32840cb5e5dSvi117747 
32940cb5e5dSvi117747 	/*
33040cb5e5dSvi117747 	 * parse isdn-subaddress
33140cb5e5dSvi117747 	 */
33240cb5e5dSvi117747 	if (uend - scan > 6 && !sip_uri_url_casecmp(scan, ";isub=", 6)) {
33340cb5e5dSvi117747 		scan += 6;
33440cb5e5dSvi117747 		mark = scan;
33540cb5e5dSvi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
33640cb5e5dSvi117747 			++scan;
33740cb5e5dSvi117747 		if (mark == scan || (scan < uend && *scan != ';'))
33840cb5e5dSvi117747 			return (0);
33940cb5e5dSvi117747 	}
34040cb5e5dSvi117747 
34140cb5e5dSvi117747 	/*
34240cb5e5dSvi117747 	 * parse post-dial
34340cb5e5dSvi117747 	 */
34440cb5e5dSvi117747 	if (uend - scan > 7 && !sip_uri_url_casecmp(scan, ";postd=", 7)) {
34540cb5e5dSvi117747 		scan += 7;
34640cb5e5dSvi117747 		mark = scan;
34740cb5e5dSvi117747 		while (scan < uend &&
34840cb5e5dSvi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
34940cb5e5dSvi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
35040cb5e5dSvi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
35140cb5e5dSvi117747 		    *scan == 'p' || *scan == 'w')) {
35240cb5e5dSvi117747 			++scan;
35340cb5e5dSvi117747 		}
35440cb5e5dSvi117747 		if (mark == scan || (scan < uend && *scan != ';'))
35540cb5e5dSvi117747 			return (0);
35640cb5e5dSvi117747 	}
35740cb5e5dSvi117747 
35840cb5e5dSvi117747 	if (!isGlobal) {
35940cb5e5dSvi117747 		/*
36040cb5e5dSvi117747 		 * parse area-specifier
36140cb5e5dSvi117747 		 */
36240cb5e5dSvi117747 		if (uend - scan > 15 &&
36340cb5e5dSvi117747 		    !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
36440cb5e5dSvi117747 			scan += 15;
36540cb5e5dSvi117747 			mark = scan;
36640cb5e5dSvi117747 			while (scan < uend && *scan != ';')
36740cb5e5dSvi117747 				++scan;
36840cb5e5dSvi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
36940cb5e5dSvi117747 		}
37040cb5e5dSvi117747 	} else {
37140cb5e5dSvi117747 		ret = 1;
37240cb5e5dSvi117747 	}
37340cb5e5dSvi117747 
37440cb5e5dSvi117747 	/*
37540cb5e5dSvi117747 	 * parse area-specifier, service-provider, future-extension
37640cb5e5dSvi117747 	 */
37740cb5e5dSvi117747 	while (scan < uend && ret) {
37840cb5e5dSvi117747 		if (uend - scan > 15 &&
37940cb5e5dSvi117747 			!sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
38040cb5e5dSvi117747 			scan += 15;
38140cb5e5dSvi117747 			mark = scan;
38240cb5e5dSvi117747 			while (scan < uend && *scan != ';')
38340cb5e5dSvi117747 				++scan;
38440cb5e5dSvi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
38540cb5e5dSvi117747 		} else if (uend - scan > 5 &&
38640cb5e5dSvi117747 		    !sip_uri_url_casecmp(scan, ";tsp=", 5)) {
38740cb5e5dSvi117747 			scan += 5;
38840cb5e5dSvi117747 			mark = scan;
38940cb5e5dSvi117747 			while (scan < uend && *scan != ';')
39040cb5e5dSvi117747 				++scan;
39140cb5e5dSvi117747 			ret = sip_uri_parse_tel_servicepro(mark, scan);
39240cb5e5dSvi117747 		} else {
39340cb5e5dSvi117747 			++scan;
39440cb5e5dSvi117747 			mark = scan;
39540cb5e5dSvi117747 			while (scan < uend && (*scan != ';' || quote)) {
39640cb5e5dSvi117747 				if (sip_uri_hexVal(scan, uend) == 0x22) {
39740cb5e5dSvi117747 					quote = !quote;
39840cb5e5dSvi117747 					scan += 3;
39940cb5e5dSvi117747 				} else {
40040cb5e5dSvi117747 					++scan;
40140cb5e5dSvi117747 				}
40240cb5e5dSvi117747 			}
40340cb5e5dSvi117747 			ret = sip_uri_parse_tel_futureext(mark, scan);
40440cb5e5dSvi117747 		}
40540cb5e5dSvi117747 	}
40640cb5e5dSvi117747 	return (ret && scan == uend);
40740cb5e5dSvi117747 }
40840cb5e5dSvi117747 
40940cb5e5dSvi117747 /*
41040cb5e5dSvi117747  * area-specifier        = ";" phone-context-tag "=" phone-context-ident
41140cb5e5dSvi117747  * phone-context-tag     = "phone-context"
41240cb5e5dSvi117747  * phone-context-ident   = network-prefix / private-prefix
41340cb5e5dSvi117747  * network-prefix        = global-network-prefix / local-network-prefix
41440cb5e5dSvi117747  * global-network-prefix = "+" 1*phonedigit
41540cb5e5dSvi117747  * local-network-prefix  = 1*(phonedigit / dtmf-digit / pause-character)
41640cb5e5dSvi117747  * private-prefix        = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
41740cb5e5dSvi117747  *                          %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
41840cb5e5dSvi117747  *                          %x65-6F / %x71-76 / %x78-7E)
41940cb5e5dSvi117747  *                          *(%x21-3A / %x3C-7E)
42040cb5e5dSvi117747  * phonedigit            = DIGIT / visual-separator
42140cb5e5dSvi117747  * visual-separator      = "-" / "." / "(" / ")"
42240cb5e5dSvi117747  * pause-character       = one-second-pause / wait-for-dial-tone
42340cb5e5dSvi117747  * one-second-pause      = "p"
42440cb5e5dSvi117747  * wait-for-dial-tone    = "w"
42540cb5e5dSvi117747  * dtmf-digit            = "*" / "#" / "A" / "B" / "C" / "D"
42640cb5e5dSvi117747  */
42740cb5e5dSvi117747 static int
42840cb5e5dSvi117747 sip_uri_parse_tel_areaspe(char *scan, char *uend)
42940cb5e5dSvi117747 {
43040cb5e5dSvi117747 	int	uri_hexValue;
43140cb5e5dSvi117747 
43240cb5e5dSvi117747 	if (scan == uend)
43340cb5e5dSvi117747 		return (0);
43440cb5e5dSvi117747 
43540cb5e5dSvi117747 	/*
43640cb5e5dSvi117747 	 * parse global-network-prefix
43740cb5e5dSvi117747 	 */
43840cb5e5dSvi117747 	if (*scan == '+') {
43940cb5e5dSvi117747 		++scan;
44040cb5e5dSvi117747 		if (scan == uend)
44140cb5e5dSvi117747 			return (0);
44240cb5e5dSvi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
44340cb5e5dSvi117747 			++scan;
44440cb5e5dSvi117747 	/*
44540cb5e5dSvi117747 	 * parse local-network-prefix
44640cb5e5dSvi117747 	 */
44740cb5e5dSvi117747 	} else if (SIP_URI_ISPHONEDIGIT(*scan) || SIP_URI_ISDTMFDIGIT(*scan) ||
44840cb5e5dSvi117747 	    sip_uri_isEscapedPound(&scan, uend) ||
44940cb5e5dSvi117747 	    *scan == 'p' || *scan == 'w') {
45040cb5e5dSvi117747 		++scan;
45140cb5e5dSvi117747 		while (scan < uend &&
45240cb5e5dSvi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
45340cb5e5dSvi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
45440cb5e5dSvi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
45540cb5e5dSvi117747 		    *scan == 'p' || *scan == 'w')) {
45640cb5e5dSvi117747 			++scan;
45740cb5e5dSvi117747 		}
45840cb5e5dSvi117747 	} else {
45940cb5e5dSvi117747 	/*
46040cb5e5dSvi117747 	 * parse private-prefix
46140cb5e5dSvi117747 	 *
46240cb5e5dSvi117747 	 * any characters allowed in RFC 2806 that are not allowed in
46340cb5e5dSvi117747 	 * the user part of the SIP URI MUST be escaped
46440cb5e5dSvi117747 	 *
46540cb5e5dSvi117747 	 * private-prefix	= (! $ & ', / = ? _
46640cb5e5dSvi117747 	 *			EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
46740cb5e5dSvi117747 	 *			{ } | ~ [ ] \ ^  ` " % : < > @)
46840cb5e5dSvi117747 	 *			*(%x21-3A / %x3C-7E)
46940cb5e5dSvi117747 	 *
47040cb5e5dSvi117747 	 * following characters are allowed in RFC 2806 and
47140cb5e5dSvi117747 	 * the user part of SIP URI
47240cb5e5dSvi117747 	 *  ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
47340cb5e5dSvi117747 	 */
47440cb5e5dSvi117747 		if (*scan == '!' || *scan == '$' || *scan == '&' ||
47540cb5e5dSvi117747 		    *scan == '\'' || *scan == ',' || *scan == '/' ||
47640cb5e5dSvi117747 		    *scan == '=' || *scan == '?' || *scan == '_' ||
47740cb5e5dSvi117747 		    (*scan >= 'E' && *scan <= 'Z' &&
47840cb5e5dSvi117747 		    *scan != 'P' && *scan != 'W') ||
47940cb5e5dSvi117747 		    (*scan >= 'e' && *scan <= 'z' &&
48040cb5e5dSvi117747 		    *scan != 'p' && *scan != 'w')) {
48140cb5e5dSvi117747 			++scan;
48240cb5e5dSvi117747 		} else {
48340cb5e5dSvi117747 			uri_hexValue = sip_uri_hexVal(scan, uend);
48440cb5e5dSvi117747 			if (uri_hexValue == 0x21 || uri_hexValue == 0x22 ||
48540cb5e5dSvi117747 			    (uri_hexValue >= 0x24 && uri_hexValue <= 0x27) ||
48640cb5e5dSvi117747 			    uri_hexValue == 0x2c || uri_hexValue == 0x2f ||
48740cb5e5dSvi117747 			    uri_hexValue == 0x3a ||
48840cb5e5dSvi117747 			    (uri_hexValue >= 0x3c && uri_hexValue <= 0x40) ||
48940cb5e5dSvi117747 			    (uri_hexValue >= 0x45 && uri_hexValue <= 0x4f) ||
49040cb5e5dSvi117747 			    (uri_hexValue >= 0x51 && uri_hexValue <= 0x56) ||
49140cb5e5dSvi117747 			    (uri_hexValue >= 0x58 && uri_hexValue <= 0x60) ||
49240cb5e5dSvi117747 			    (uri_hexValue >= 0x65 && uri_hexValue <= 0x6f) ||
49340cb5e5dSvi117747 			    (uri_hexValue >= 0x71 && uri_hexValue <= 0x76) ||
49440cb5e5dSvi117747 			    (uri_hexValue >= 0x78 && uri_hexValue <= 0x7e)) {
49540cb5e5dSvi117747 				scan += 3;
49640cb5e5dSvi117747 			} else {
49740cb5e5dSvi117747 				return (0);
49840cb5e5dSvi117747 			}
49940cb5e5dSvi117747 		}
50040cb5e5dSvi117747 		/*
50140cb5e5dSvi117747 		 * parse *(%x21-3A / %x3C-7E)
50240cb5e5dSvi117747 		 */
50340cb5e5dSvi117747 		while (scan < uend) {
50440cb5e5dSvi117747 			if (SIP_URI_ISUNRESERVED(*scan) ||
50540cb5e5dSvi117747 			    (SIP_URI_ISUSER(*scan) && *scan != ';')) {
50640cb5e5dSvi117747 				++scan;
50740cb5e5dSvi117747 			} else {
50840cb5e5dSvi117747 				uri_hexValue = sip_uri_hexVal(scan, uend);
50940cb5e5dSvi117747 				if (uri_hexValue >= 0x21 &&
51040cb5e5dSvi117747 				    uri_hexValue <= 0x7e &&
51140cb5e5dSvi117747 				    uri_hexValue != 0x3b) {
51240cb5e5dSvi117747 					scan += 3;
51340cb5e5dSvi117747 				} else {
51440cb5e5dSvi117747 					return (0);
51540cb5e5dSvi117747 				}
51640cb5e5dSvi117747 			}
51740cb5e5dSvi117747 		}
51840cb5e5dSvi117747 	}
51940cb5e5dSvi117747 	if (scan < uend)
52040cb5e5dSvi117747 		return (0);
52140cb5e5dSvi117747 	return (1);
52240cb5e5dSvi117747 }
52340cb5e5dSvi117747 
52440cb5e5dSvi117747 static int
52540cb5e5dSvi117747 sip_uri_hexVal(char *scan, char *uend)
52640cb5e5dSvi117747 {
52740cb5e5dSvi117747 	int	ret = -1;
52840cb5e5dSvi117747 
52940cb5e5dSvi117747 	if (SIP_URI_ISURLESCAPE(scan, uend)) {
53040cb5e5dSvi117747 		ret = (SIP_URI_ISDIGIT(scan[1]) ? (scan[1] - '0') :
53140cb5e5dSvi117747 		    (tolower(scan[1]) - 'a' + 10)) * 16 +
53240cb5e5dSvi117747 		    (SIP_URI_ISDIGIT(scan[2]) ? (scan[2] - '0') :
53340cb5e5dSvi117747 		    (tolower(scan[2]) - 'a' + 10));
53440cb5e5dSvi117747 	}
53540cb5e5dSvi117747 	return (ret);
53640cb5e5dSvi117747 }
53740cb5e5dSvi117747 
53840cb5e5dSvi117747 /*
53940cb5e5dSvi117747  * service-provider  = ";" provider-tag "=" provider-hostname
54040cb5e5dSvi117747  * provider-tag      = "tsp"
54140cb5e5dSvi117747  * provider-hostname = domain
54240cb5e5dSvi117747  */
54340cb5e5dSvi117747 static int
54440cb5e5dSvi117747 sip_uri_parse_tel_servicepro(char *scan, char *uend)
54540cb5e5dSvi117747 {
54640cb5e5dSvi117747 	char	*mark = (char *)0;
54740cb5e5dSvi117747 
54840cb5e5dSvi117747 	if (scan == uend)
54940cb5e5dSvi117747 		return (0);
55040cb5e5dSvi117747 
55140cb5e5dSvi117747 	/*
55240cb5e5dSvi117747 	 * parse domain=" "
55340cb5e5dSvi117747 	 */
55440cb5e5dSvi117747 	if (sip_uri_hexVal(scan, uend) == 0x20 && scan + 3 == uend)
55540cb5e5dSvi117747 		return (1);
55640cb5e5dSvi117747 	while (scan < uend) {
55740cb5e5dSvi117747 		mark = scan;
55840cb5e5dSvi117747 		while (scan < uend && (*scan == '-'|| SIP_URI_ISALNUM(*scan)))
55940cb5e5dSvi117747 			++scan;
56040cb5e5dSvi117747 		if ((scan < uend && *scan != '.') ||
56140cb5e5dSvi117747 		    !SIP_URI_ISALPHA(*mark) || !SIP_URI_ISALNUM(*(scan - 1))) {
56240cb5e5dSvi117747 			return (0);
56340cb5e5dSvi117747 		}
56440cb5e5dSvi117747 		if (scan < uend)
56540cb5e5dSvi117747 			++scan;
56640cb5e5dSvi117747 	}
56740cb5e5dSvi117747 
56840cb5e5dSvi117747 	if (scan < uend)
56940cb5e5dSvi117747 		return (0);
57040cb5e5dSvi117747 	return (1);
57140cb5e5dSvi117747 }
57240cb5e5dSvi117747 
57340cb5e5dSvi117747 /*
57440cb5e5dSvi117747  * future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
57540cb5e5dSvi117747  *                    ["?" 1*(token-char)]) / quoted-string )]
57640cb5e5dSvi117747  * token-char       = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
57740cb5e5dSvi117747  *                     / %x41-5A / %x5E-7A / %x7C / %x7E)
57840cb5e5dSvi117747  */
57940cb5e5dSvi117747 static int
58040cb5e5dSvi117747 sip_uri_parse_tel_futureext(char *scan, char *uend)
58140cb5e5dSvi117747 {
58240cb5e5dSvi117747 	char	*mark;
58340cb5e5dSvi117747 	int	uri_hexValue = 0;
58440cb5e5dSvi117747 
58540cb5e5dSvi117747 	if (scan == uend)
58640cb5e5dSvi117747 		return (0);
58740cb5e5dSvi117747 
58840cb5e5dSvi117747 	/*
58940cb5e5dSvi117747 	 * parse 1*(token-char)
59040cb5e5dSvi117747 	 */
59140cb5e5dSvi117747 	mark = scan;
59240cb5e5dSvi117747 	while (scan < uend && sip_uri_isTokenchar(&scan, uend))
59340cb5e5dSvi117747 		;
59440cb5e5dSvi117747 	if (mark == scan ||
59540cb5e5dSvi117747 	    (scan < uend && (*scan != '=' || scan + 1 == uend))) {
59640cb5e5dSvi117747 		return (0);
59740cb5e5dSvi117747 	}
59840cb5e5dSvi117747 	if (scan == uend)
59940cb5e5dSvi117747 		return (1);
60040cb5e5dSvi117747 	++scan;
60140cb5e5dSvi117747 
60240cb5e5dSvi117747 	/*
60340cb5e5dSvi117747 	 * parse 1*token-char ["?" 1*token-char]
60440cb5e5dSvi117747 	 */
60540cb5e5dSvi117747 	if (sip_uri_isTokenchar(&scan, uend)) {
60640cb5e5dSvi117747 		while (sip_uri_isTokenchar(&scan, uend))
60740cb5e5dSvi117747 			;
60840cb5e5dSvi117747 		if (scan < uend) {
60940cb5e5dSvi117747 			if (*scan != '?')
61040cb5e5dSvi117747 				return (0);
61140cb5e5dSvi117747 			++scan;
61240cb5e5dSvi117747 			mark = scan;
61340cb5e5dSvi117747 			while (sip_uri_isTokenchar(&scan, uend))
61440cb5e5dSvi117747 				;
61540cb5e5dSvi117747 			if (mark == scan)
61640cb5e5dSvi117747 				return (0);
61740cb5e5dSvi117747 		}
61840cb5e5dSvi117747 	} else { /* parse quoted-string */
61940cb5e5dSvi117747 		uri_hexValue = sip_uri_hexVal(scan, uend);
62040cb5e5dSvi117747 		if (uri_hexValue != 0x22)
62140cb5e5dSvi117747 			return (0);
62240cb5e5dSvi117747 		scan += 3;
62340cb5e5dSvi117747 		while (scan < uend && sip_uri_hexVal(scan, uend) != 0x22) {
62440cb5e5dSvi117747 			/*
62540cb5e5dSvi117747 			 * parse "\" CHAR
62640cb5e5dSvi117747 			 */
62740cb5e5dSvi117747 			if (sip_uri_hexVal(scan, uend) == 0x5c) {
62840cb5e5dSvi117747 				scan += 3;
62940cb5e5dSvi117747 				if (scan < uend) {
63040cb5e5dSvi117747 					if (SIP_URI_ISUNRESERVED(*scan) ||
63140cb5e5dSvi117747 					    SIP_URI_ISUSER(*scan)) {
63240cb5e5dSvi117747 						++scan;
63340cb5e5dSvi117747 					} else if (sip_uri_hexVal(scan, uend) >=
63440cb5e5dSvi117747 					    0x00 &&
63540cb5e5dSvi117747 					    sip_uri_hexVal(scan, uend) <=
63640cb5e5dSvi117747 					    0x7f) {
63740cb5e5dSvi117747 						scan += 3;
63840cb5e5dSvi117747 					} else {
63940cb5e5dSvi117747 						return (0);
64040cb5e5dSvi117747 					}
64140cb5e5dSvi117747 				} else {
64240cb5e5dSvi117747 					return (0);
64340cb5e5dSvi117747 				}
64440cb5e5dSvi117747 			} else {
64540cb5e5dSvi117747 				if (SIP_URI_ISUNRESERVED(*scan) ||
64640cb5e5dSvi117747 				    SIP_URI_ISUSER(*scan)) {
64740cb5e5dSvi117747 					++scan;
64840cb5e5dSvi117747 				} else {
64940cb5e5dSvi117747 					uri_hexValue =
65040cb5e5dSvi117747 					    sip_uri_hexVal(scan, uend);
65140cb5e5dSvi117747 					if ((uri_hexValue >= 0x20 &&
65240cb5e5dSvi117747 						uri_hexValue <= 0x21) ||
65340cb5e5dSvi117747 						(uri_hexValue >= 0x23 &&
65440cb5e5dSvi117747 						uri_hexValue <= 0x7e) ||
65540cb5e5dSvi117747 						(uri_hexValue >= 0x80 &&
65640cb5e5dSvi117747 						uri_hexValue <= 0xff)) {
65740cb5e5dSvi117747 						scan += 3;
65840cb5e5dSvi117747 					} else {
65940cb5e5dSvi117747 						return (0);
66040cb5e5dSvi117747 					}
66140cb5e5dSvi117747 				}
66240cb5e5dSvi117747 			}
66340cb5e5dSvi117747 		}
66440cb5e5dSvi117747 		if (scan == uend ||
66540cb5e5dSvi117747 		    (scan < uend && sip_uri_hexVal(scan, uend) != 0x22)) {
66640cb5e5dSvi117747 			return (0);
66740cb5e5dSvi117747 		}
66840cb5e5dSvi117747 		scan += 3;
66940cb5e5dSvi117747 	}
67040cb5e5dSvi117747 
67140cb5e5dSvi117747 	if (scan < uend)
67240cb5e5dSvi117747 		return (0);
67340cb5e5dSvi117747 	return (1);
67440cb5e5dSvi117747 }
67540cb5e5dSvi117747 
67640cb5e5dSvi117747 /*
67740cb5e5dSvi117747  * Any characters allowed in RFC2806 tel URL that are not allowed in
67840cb5e5dSvi117747  * the user part of the SIP URI MUST be escaped.
67940cb5e5dSvi117747  * token-char = - _ . ! ~ * ' $ &  + DIGIT ALPHA #  % ^ ` |
68040cb5e5dSvi117747  */
68140cb5e5dSvi117747 static int
68240cb5e5dSvi117747 sip_uri_isTokenchar(char **pscan, char *uend)
68340cb5e5dSvi117747 {
68440cb5e5dSvi117747 	char	*scan = *pscan;
68540cb5e5dSvi117747 	int	uri_hexValue = 0;
68640cb5e5dSvi117747 
68740cb5e5dSvi117747 	if (scan == uend)
68840cb5e5dSvi117747 		return (0);
68940cb5e5dSvi117747 
69040cb5e5dSvi117747 	/*
69140cb5e5dSvi117747 	 * for ALPAH DIGIT - _ . ! ~ * ' $ & +
69240cb5e5dSvi117747 	 */
69340cb5e5dSvi117747 	if ((SIP_URI_ISUNRESERVED(*scan) && *scan != '(' && *scan != ')') ||
69440cb5e5dSvi117747 	    *scan == '$' || *scan == '&' || *scan == '+') {
69540cb5e5dSvi117747 		++scan;
69640cb5e5dSvi117747 		*pscan = scan;
69740cb5e5dSvi117747 		return (1);
69840cb5e5dSvi117747 	}
69940cb5e5dSvi117747 
70040cb5e5dSvi117747 	uri_hexValue = sip_uri_hexVal(scan, uend);
70140cb5e5dSvi117747 	if (uri_hexValue == 0x21 || uri_hexValue == 0x7c ||
70240cb5e5dSvi117747 	    uri_hexValue == 0x7e ||
70340cb5e5dSvi117747 	    (uri_hexValue >= 0x23 && uri_hexValue <= 0x27) ||
70440cb5e5dSvi117747 	    (uri_hexValue >= 0x2a && uri_hexValue <= 0x2b) ||
70540cb5e5dSvi117747 	    (uri_hexValue >= 0x2d && uri_hexValue <= 0x2e) ||
70640cb5e5dSvi117747 	    (uri_hexValue >= 0x30 && uri_hexValue <= 0x39) ||
70740cb5e5dSvi117747 	    (uri_hexValue >= 0x41 && uri_hexValue <= 0x5a) ||
70840cb5e5dSvi117747 	    (uri_hexValue >= 0x5e && uri_hexValue <= 0x7a)) {
70940cb5e5dSvi117747 		scan += 3;
71040cb5e5dSvi117747 		*pscan = scan;
71140cb5e5dSvi117747 		return (1);
71240cb5e5dSvi117747 	}
71340cb5e5dSvi117747 	return (0);
71440cb5e5dSvi117747 }
71540cb5e5dSvi117747 
71640cb5e5dSvi117747 /*
71740cb5e5dSvi117747  * '#' is not allowed in the telephone-subscriber part of SIP URI
71840cb5e5dSvi117747  * it must be escaped
71940cb5e5dSvi117747  */
72040cb5e5dSvi117747 static int
72140cb5e5dSvi117747 sip_uri_isEscapedPound(char **pscan, char *uend)
72240cb5e5dSvi117747 {
72340cb5e5dSvi117747 	char	*scan = *pscan;
72440cb5e5dSvi117747 
72540cb5e5dSvi117747 	if (scan == uend)
72640cb5e5dSvi117747 		return (0);
72740cb5e5dSvi117747 	if (*scan == '%' && scan + 2 < uend && scan[1] == '2' &&
72840cb5e5dSvi117747 	    scan[2] == '3') {
72940cb5e5dSvi117747 		scan += 2;
73040cb5e5dSvi117747 		*pscan = scan;
73140cb5e5dSvi117747 		return (1);
73240cb5e5dSvi117747 	}
73340cb5e5dSvi117747 	return (0);
73440cb5e5dSvi117747 }
73540cb5e5dSvi117747 
73640cb5e5dSvi117747 /*
73740cb5e5dSvi117747  * scheme =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
73840cb5e5dSvi117747  */
73940cb5e5dSvi117747 static int
74040cb5e5dSvi117747 sip_uri_parse_scheme(_sip_uri_t *outurl, char *scan, char *uend)
74140cb5e5dSvi117747 {
74240cb5e5dSvi117747 	if (scan == uend) {
74340cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
74440cb5e5dSvi117747 		return (0);
74540cb5e5dSvi117747 	}
74640cb5e5dSvi117747 	outurl->sip_uri_scheme.sip_str_ptr = scan;
74740cb5e5dSvi117747 	outurl->sip_uri_scheme.sip_str_len = uend - scan;
74840cb5e5dSvi117747 
74940cb5e5dSvi117747 	if (scan < uend && SIP_URI_ISALPHA(*scan)) {
75040cb5e5dSvi117747 		++scan;
75140cb5e5dSvi117747 		while (scan < uend && SIP_URI_ISSCHEME(*scan))
75240cb5e5dSvi117747 			++scan;
75340cb5e5dSvi117747 	}
75440cb5e5dSvi117747 	if (scan < uend)
75540cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
75640cb5e5dSvi117747 	return (1);
75740cb5e5dSvi117747 }
75840cb5e5dSvi117747 
75940cb5e5dSvi117747 /*
76040cb5e5dSvi117747  * The format of params is supposed to be;XXX;XXX;XXX
76140cb5e5dSvi117747  * uri-parameters	= *(";" uri-parameter)
76240cb5e5dSvi117747  * uri-parameter	= transport-param / user-param / method-param
76340cb5e5dSvi117747  * 			/ ttl-param / maddr-param / lr-param / other-param
76440cb5e5dSvi117747  * transport-param	=  "transport="
76540cb5e5dSvi117747  *			("udp" / "tcp" / "sctp" / "tls" / other-transport)
76640cb5e5dSvi117747  * other-transport		=  token
76740cb5e5dSvi117747  * user-param		=  "user=" ("phone" / "ip" / other-user)
76840cb5e5dSvi117747  * other-user		=  token
76940cb5e5dSvi117747  * method-param		=  "method=" Method
77040cb5e5dSvi117747  * ttl-param		=  "ttl=" ttl
77140cb5e5dSvi117747  * maddr-param		=  "maddr=" host
77240cb5e5dSvi117747  * lr-param		=  "lr"
77340cb5e5dSvi117747  * other-param		=  pname [ "=" pvalue ]
77440cb5e5dSvi117747  * pname		=  1*paramchar
77540cb5e5dSvi117747  * pvalue		=  1*paramchar
77640cb5e5dSvi117747  * paramchar		=  param-unreserved / unreserved / escaped
77740cb5e5dSvi117747  * param-unreserved	=  "[" / "]" / "/" / ":" / "&" / "+" / "$"
77840cb5e5dSvi117747  */
77940cb5e5dSvi117747 static void
78040cb5e5dSvi117747 sip_uri_parse_params(_sip_uri_t *outurl, char *scan, char *uend)
78140cb5e5dSvi117747 {
78240cb5e5dSvi117747 	char		*mark = (char *)0;
78340cb5e5dSvi117747 	char		*equal = (char *)0;
78440cb5e5dSvi117747 	int		i = 0;
78540cb5e5dSvi117747 	int		ttl = 0;
78640cb5e5dSvi117747 	int		paramleftlen = 0;
78740cb5e5dSvi117747 	int		gothost = 0;
78840cb5e5dSvi117747 	sip_param_t	*param = NULL;
78940cb5e5dSvi117747 	sip_param_t	*new_param = NULL;
79040cb5e5dSvi117747 
79140cb5e5dSvi117747 	if (scan == uend || *scan != ';' || scan + 1 == uend) {
79240cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
79340cb5e5dSvi117747 		return;
79440cb5e5dSvi117747 	}
79540cb5e5dSvi117747 
79640cb5e5dSvi117747 	while (scan < uend) {
79740cb5e5dSvi117747 		mark = ++scan;
79840cb5e5dSvi117747 		while (scan < uend && *scan != ';')
79940cb5e5dSvi117747 			++scan;
80040cb5e5dSvi117747 		if (scan == mark) {
80140cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
80240cb5e5dSvi117747 			return;
80340cb5e5dSvi117747 		}
80440cb5e5dSvi117747 
80540cb5e5dSvi117747 		new_param = calloc(1, sizeof (sip_param_t));
80640cb5e5dSvi117747 		if (new_param == NULL) {
80740cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_MEMORY;
80840cb5e5dSvi117747 			return;
80940cb5e5dSvi117747 		}
81040cb5e5dSvi117747 
81140cb5e5dSvi117747 		if (param == NULL)
81240cb5e5dSvi117747 			outurl->sip_uri_params = new_param;
81340cb5e5dSvi117747 		else
81440cb5e5dSvi117747 			param->param_next = new_param;
81540cb5e5dSvi117747 
81640cb5e5dSvi117747 		param = new_param;
81740cb5e5dSvi117747 
81840cb5e5dSvi117747 		param->param_name.sip_str_ptr = mark;
81940cb5e5dSvi117747 		equal = memchr(mark, '=', scan - mark);
82040cb5e5dSvi117747 		if (equal == (char *)0) {
82140cb5e5dSvi117747 			param->param_name.sip_str_len = scan - mark;
82240cb5e5dSvi117747 			param->param_value.sip_str_ptr = NULL;
82340cb5e5dSvi117747 			param->param_value.sip_str_len = 0;
82440cb5e5dSvi117747 			while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
82540cb5e5dSvi117747 			    SIP_URI_ISURLESCAPE(mark, scan))) {
82640cb5e5dSvi117747 				++mark;
82740cb5e5dSvi117747 			}
82840cb5e5dSvi117747 		} else {
82940cb5e5dSvi117747 			param->param_name.sip_str_len = equal - mark;
83040cb5e5dSvi117747 			param->param_value.sip_str_ptr = equal + 1;
83140cb5e5dSvi117747 			param->param_value.sip_str_len = scan - equal - 1;
83240cb5e5dSvi117747 
83340cb5e5dSvi117747 			if (mark == equal || equal + 1 == scan) {
83440cb5e5dSvi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
83540cb5e5dSvi117747 				return;
83640cb5e5dSvi117747 			}
83740cb5e5dSvi117747 			paramleftlen = equal - mark + 1;
83840cb5e5dSvi117747 			if ((paramleftlen == 10 &&
83940cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "transport=", 10)) ||
84040cb5e5dSvi117747 			    (paramleftlen == 5 &&
84140cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "user=", 5)) ||
84240cb5e5dSvi117747 			    (paramleftlen == 7 &&
84340cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "method=", 7))) {
84440cb5e5dSvi117747 				if (scan - equal == 1) {
84540cb5e5dSvi117747 					outurl->sip_uri_errflags |=
84640cb5e5dSvi117747 					    SIP_URIERR_PARAM;
84740cb5e5dSvi117747 					return;
84840cb5e5dSvi117747 				}
84940cb5e5dSvi117747 				mark = equal + 1;
85040cb5e5dSvi117747 				while (mark < scan && SIP_URI_ISTOKEN(*mark))
85140cb5e5dSvi117747 					++mark;
85240cb5e5dSvi117747 			} else if (paramleftlen == 4 &&
85340cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "ttl=", 4)) {
85440cb5e5dSvi117747 				if (scan - equal == 1) {
85540cb5e5dSvi117747 					outurl->sip_uri_errflags |=
85640cb5e5dSvi117747 					    SIP_URIERR_PARAM;
85740cb5e5dSvi117747 					return;
85840cb5e5dSvi117747 				}
85940cb5e5dSvi117747 				mark = equal;
86040cb5e5dSvi117747 				for (i = 0; i < 3; ++i) {
86140cb5e5dSvi117747 					++mark;
86240cb5e5dSvi117747 					if (mark < scan &&
86340cb5e5dSvi117747 					    SIP_URI_ISDIGIT(*mark)) {
86440cb5e5dSvi117747 						ttl = ttl * 10 + (*mark - '0');
86540cb5e5dSvi117747 					}
86640cb5e5dSvi117747 					if (ttl > 255) {
86740cb5e5dSvi117747 						outurl->sip_uri_errflags |=
86840cb5e5dSvi117747 							SIP_URIERR_PARAM;
86940cb5e5dSvi117747 						return;
87040cb5e5dSvi117747 					}
87140cb5e5dSvi117747 				}
87240cb5e5dSvi117747 			} else if (paramleftlen == 6 &&
87340cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "maddr=", 6)) {
87440cb5e5dSvi117747 				gothost = 0;
87540cb5e5dSvi117747 				mark = equal + 1;
87640cb5e5dSvi117747 				if (mark < scan && SIP_URI_ISDIGIT(*mark)) {
87740cb5e5dSvi117747 					gothost = sip_uri_parse_ipv4(mark,
87840cb5e5dSvi117747 					    scan);
87940cb5e5dSvi117747 				}
88040cb5e5dSvi117747 				/*
88140cb5e5dSvi117747 				 * not valid syntax for a host or user name,
88240cb5e5dSvi117747 				 * try IPv6 literal
88340cb5e5dSvi117747 				 */
88440cb5e5dSvi117747 				if (!gothost && mark < scan && *mark == '[') {
88540cb5e5dSvi117747 					gothost = sip_uri_parse_ipv6(mark,
88640cb5e5dSvi117747 					    scan);
88740cb5e5dSvi117747 				}
88840cb5e5dSvi117747 				/*
88940cb5e5dSvi117747 				 * look for a valid host name:
89040cb5e5dSvi117747 				 * *(domainlabel ".") toplabel ["."]
89140cb5e5dSvi117747 				 */
89240cb5e5dSvi117747 				if (!gothost && mark < scan) {
89340cb5e5dSvi117747 					if (!(gothost =
89440cb5e5dSvi117747 					    sip_uri_parse_hostname(mark,
89540cb5e5dSvi117747 					    scan))) {
89640cb5e5dSvi117747 						outurl->sip_uri_errflags |=
89740cb5e5dSvi117747 							SIP_URIERR_PARAM;
89840cb5e5dSvi117747 					}
89940cb5e5dSvi117747 				}
90040cb5e5dSvi117747 				if (gothost)
90140cb5e5dSvi117747 					mark = scan;
90240cb5e5dSvi117747 			} else if (paramleftlen == 3 &&
90340cb5e5dSvi117747 			    !sip_uri_url_casecmp(mark, "lr=", 3)) {
90440cb5e5dSvi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
90540cb5e5dSvi117747 				return;
90640cb5e5dSvi117747 			} else {
90740cb5e5dSvi117747 				while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
90840cb5e5dSvi117747 				    SIP_URI_ISURLESCAPE(mark, scan) ||
90940cb5e5dSvi117747 				    mark == equal)) {
91040cb5e5dSvi117747 					++mark;
91140cb5e5dSvi117747 				}
91240cb5e5dSvi117747 			}
91340cb5e5dSvi117747 		}
91440cb5e5dSvi117747 		if (mark < scan) {
91540cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
91640cb5e5dSvi117747 			return;
91740cb5e5dSvi117747 		}
91840cb5e5dSvi117747 	}
91940cb5e5dSvi117747 }
92040cb5e5dSvi117747 
92140cb5e5dSvi117747 /*
92240cb5e5dSvi117747  * The format of headers is supposed to be ?XXX&XXX&XXX
92340cb5e5dSvi117747  * headers         =  "?" header *("&" header
92440cb5e5dSvi117747  * header          =  hname "=" hvalue
92540cb5e5dSvi117747  * hname           =  1*(hnv-unreserved / unreserved / escaped
92640cb5e5dSvi117747  * hvalue          =  *(hnv-unreserved / unreserved / escaped
92740cb5e5dSvi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
92840cb5e5dSvi117747  */
92940cb5e5dSvi117747 static void
93040cb5e5dSvi117747 sip_uri_parse_headers(_sip_uri_t *outurl, char *scan, char *uend)
93140cb5e5dSvi117747 {
93240cb5e5dSvi117747 	char	*mark = NULL;
93340cb5e5dSvi117747 	char	*equal = NULL;
93440cb5e5dSvi117747 
93540cb5e5dSvi117747 	if (scan == uend || *scan != '?' || scan + 1 == uend) {
93640cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
93740cb5e5dSvi117747 		return;
93840cb5e5dSvi117747 	}
93940cb5e5dSvi117747 	outurl->sip_uri_headers.sip_str_ptr = scan + 1;
94040cb5e5dSvi117747 	outurl->sip_uri_headers.sip_str_len = uend - (scan + 1);
94140cb5e5dSvi117747 
94240cb5e5dSvi117747 	while (scan < uend) {
94340cb5e5dSvi117747 		mark = ++scan;
94440cb5e5dSvi117747 		while (scan < uend && *scan != '&')
94540cb5e5dSvi117747 			++scan;
94640cb5e5dSvi117747 		if (scan == mark) {
94740cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
94840cb5e5dSvi117747 			return;
94940cb5e5dSvi117747 		}
95040cb5e5dSvi117747 		equal = memchr(mark, '=', scan - mark);
95140cb5e5dSvi117747 		if (equal == mark || equal == (char *)0) {
95240cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
95340cb5e5dSvi117747 			return;
95440cb5e5dSvi117747 		}
95540cb5e5dSvi117747 		while (mark < scan &&
95640cb5e5dSvi117747 		    (SIP_URI_ISHEADER(*mark) ||
95740cb5e5dSvi117747 		    SIP_URI_ISURLESCAPE(mark, scan) || mark == equal)) {
95840cb5e5dSvi117747 			++mark;
95940cb5e5dSvi117747 		}
96040cb5e5dSvi117747 		if (mark < scan) {
96140cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
96240cb5e5dSvi117747 			return;
96340cb5e5dSvi117747 		}
96440cb5e5dSvi117747 	}
96540cb5e5dSvi117747 }
96640cb5e5dSvi117747 
96740cb5e5dSvi117747 /*
96840cb5e5dSvi117747  * opaque-part   =  uric-no-slash *uric
96940cb5e5dSvi117747  * uric          =  reserved / unreserved / escaped
97040cb5e5dSvi117747  * uric-no-slash =  unreserved / escaped / ";" / "?" / ":" / "@"
97140cb5e5dSvi117747  *                  / "&" / "=" / "+" / "$" / ","
97240cb5e5dSvi117747  */
97340cb5e5dSvi117747 static void
97440cb5e5dSvi117747 sip_uri_parse_abs_opaque(_sip_uri_t *outurl, char *scan, char *uend)
97540cb5e5dSvi117747 {
97640cb5e5dSvi117747 	if (scan == uend) {
97740cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
97840cb5e5dSvi117747 		return;
97940cb5e5dSvi117747 	}
98040cb5e5dSvi117747 	outurl->sip_uri_opaque.sip_str_ptr = scan;
98140cb5e5dSvi117747 	outurl->sip_uri_opaque.sip_str_len = uend - scan;
98240cb5e5dSvi117747 
98340cb5e5dSvi117747 	if (SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
98440cb5e5dSvi117747 	    SIP_URI_ISOTHER(*scan) || *scan == ';' || *scan == '?' ||
98540cb5e5dSvi117747 	    *scan == ':' || *scan == '@' || *scan == '&') {
98640cb5e5dSvi117747 		++scan;
98740cb5e5dSvi117747 	} else {
98840cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
98940cb5e5dSvi117747 		return;
99040cb5e5dSvi117747 	}
99140cb5e5dSvi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
99240cb5e5dSvi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
99340cb5e5dSvi117747 		++scan;
99440cb5e5dSvi117747 	}
99540cb5e5dSvi117747 	if (scan < uend)
99640cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
99740cb5e5dSvi117747 }
99840cb5e5dSvi117747 
99940cb5e5dSvi117747 /*
100040cb5e5dSvi117747  * format of query is supposed to be ?XXX
100140cb5e5dSvi117747  * query =  *uric
100240cb5e5dSvi117747  * uric  =  reserved / unreserved / escaped
100340cb5e5dSvi117747  */
100440cb5e5dSvi117747 static void
100540cb5e5dSvi117747 sip_uri_parse_abs_query(_sip_uri_t *outurl, char *scan, char *uend)
100640cb5e5dSvi117747 {
100740cb5e5dSvi117747 	if (uend == scan || *scan != '?' || scan + 1 == uend)
100840cb5e5dSvi117747 		return;
100940cb5e5dSvi117747 	++scan;
101040cb5e5dSvi117747 	outurl->sip_uri_query.sip_str_ptr = scan;
101140cb5e5dSvi117747 	outurl->sip_uri_query.sip_str_len = uend - scan;
101240cb5e5dSvi117747 
101340cb5e5dSvi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
101440cb5e5dSvi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
101540cb5e5dSvi117747 		++scan;
101640cb5e5dSvi117747 	}
101740cb5e5dSvi117747 	if (scan < uend)
101840cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_QUERY;
101940cb5e5dSvi117747 }
102040cb5e5dSvi117747 
102140cb5e5dSvi117747 /*
102240cb5e5dSvi117747  * the format of path is supposed to be /XXX;XXX/XXX;
102340cb5e5dSvi117747  * abs-path       =  "/" path-segments
102440cb5e5dSvi117747  * path-segments  =  segment *( "/" segment )
102540cb5e5dSvi117747  * segment        =  *pchar *( ";" param )
102640cb5e5dSvi117747  * param          =  *pchar
102740cb5e5dSvi117747  * pchar          =  unreserved / escaped /
102840cb5e5dSvi117747  *                   ":" / "@" / "&" / "=" / "+" / "$" / ","
102940cb5e5dSvi117747  */
103040cb5e5dSvi117747 static void
103140cb5e5dSvi117747 sip_uri_parse_abs_path(_sip_uri_t *outurl, char *scan, char *uend)
103240cb5e5dSvi117747 {
103340cb5e5dSvi117747 	if (scan == uend || *scan != '/')
103440cb5e5dSvi117747 		return;
103540cb5e5dSvi117747 	outurl->sip_uri_path.sip_str_ptr = scan;
103640cb5e5dSvi117747 	outurl->sip_uri_path.sip_str_len = uend - scan;
103740cb5e5dSvi117747 
103840cb5e5dSvi117747 	++scan;
103940cb5e5dSvi117747 	while (scan < uend && (SIP_URI_ISPCHAR(*scan) ||
104040cb5e5dSvi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
104140cb5e5dSvi117747 	    *scan == '/' || *scan == ';')) {
104240cb5e5dSvi117747 		++scan;
104340cb5e5dSvi117747 	}
104440cb5e5dSvi117747 	if (scan < uend)
104540cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PATH;
104640cb5e5dSvi117747 }
104740cb5e5dSvi117747 /*
104840cb5e5dSvi117747  * reg-name =  1*( unreserved / escaped / "$" / "," / ";"
104940cb5e5dSvi117747  *             / ":" / "@" / "&" / "=" / "+" )
105040cb5e5dSvi117747  */
105140cb5e5dSvi117747 static void
105240cb5e5dSvi117747 sip_uri_parse_abs_regname(_sip_uri_t *outurl, char *scan, char *uend)
105340cb5e5dSvi117747 {
105440cb5e5dSvi117747 	if (scan == uend)
105540cb5e5dSvi117747 		return;
105640cb5e5dSvi117747 	outurl->sip_uri_regname.sip_str_ptr = scan;
105740cb5e5dSvi117747 	outurl->sip_uri_regname.sip_str_len = uend - scan;
105840cb5e5dSvi117747 
105940cb5e5dSvi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
106040cb5e5dSvi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISREGNAME(*scan))) {
106140cb5e5dSvi117747 		++scan;
106240cb5e5dSvi117747 	}
106340cb5e5dSvi117747 	if (scan < uend)
106440cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_REGNAME;
106540cb5e5dSvi117747 }
106640cb5e5dSvi117747 
106740cb5e5dSvi117747 /*
106840cb5e5dSvi117747  * The format of the password is supposed to be :XXX
106940cb5e5dSvi117747  * password =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
107040cb5e5dSvi117747  */
107140cb5e5dSvi117747 static void
107240cb5e5dSvi117747 sip_uri_parse_password(_sip_uri_t *outurl, char *scan, char *uend)
107340cb5e5dSvi117747 {
107440cb5e5dSvi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend)
107540cb5e5dSvi117747 		return;
107640cb5e5dSvi117747 	++scan;
107740cb5e5dSvi117747 	outurl->sip_uri_password.sip_str_ptr = scan;
107840cb5e5dSvi117747 	outurl->sip_uri_password.sip_str_len = uend - scan;
107940cb5e5dSvi117747 
108040cb5e5dSvi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
108140cb5e5dSvi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISOTHER(*scan) ||
108240cb5e5dSvi117747 	    *scan == '&')) {
108340cb5e5dSvi117747 		++scan;
108440cb5e5dSvi117747 	}
108540cb5e5dSvi117747 	if (scan < uend)
108640cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PASS;
108740cb5e5dSvi117747 }
108840cb5e5dSvi117747 
108940cb5e5dSvi117747 /*
109040cb5e5dSvi117747  * user =  1*( unreserved / escaped / user-unreserved )
109140cb5e5dSvi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
109240cb5e5dSvi117747  */
109340cb5e5dSvi117747 static void
109440cb5e5dSvi117747 sip_uri_parse_user(_sip_uri_t *outurl, char *scan, char *uend)
109540cb5e5dSvi117747 {
109640cb5e5dSvi117747 	if (scan == uend) {
109740cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_USER;
109840cb5e5dSvi117747 		return;
109940cb5e5dSvi117747 	}
110040cb5e5dSvi117747 	outurl->sip_uri_user.sip_str_ptr = scan;
110140cb5e5dSvi117747 	outurl->sip_uri_user.sip_str_len = uend - scan;
110240cb5e5dSvi117747 
110340cb5e5dSvi117747 	if (sip_uri_parse_tel(scan, uend)) {
110440cb5e5dSvi117747 		outurl->sip_uri_isteluser = B_TRUE;
110540cb5e5dSvi117747 	} else {
110640cb5e5dSvi117747 		while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
110740cb5e5dSvi117747 		    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISUSER(*scan))) {
110840cb5e5dSvi117747 			++scan;
110940cb5e5dSvi117747 		}
111040cb5e5dSvi117747 		if (scan < uend)
111140cb5e5dSvi117747 			outurl->sip_uri_errflags |= SIP_URIERR_USER;
111240cb5e5dSvi117747 	}
111340cb5e5dSvi117747 }
111440cb5e5dSvi117747 
111540cb5e5dSvi117747 /*
111640cb5e5dSvi117747  * the format of port is supposed to be :XXX
111740cb5e5dSvi117747  * port =  1*DIGIT
111840cb5e5dSvi117747  */
111940cb5e5dSvi117747 static void
112040cb5e5dSvi117747 sip_uri_parse_port(_sip_uri_t *outurl, char *scan, char *uend)
112140cb5e5dSvi117747 {
112240cb5e5dSvi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend) {
112340cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
112440cb5e5dSvi117747 		return;
112540cb5e5dSvi117747 	}
112640cb5e5dSvi117747 	++scan;
112740cb5e5dSvi117747 	/*
112840cb5e5dSvi117747 	 * parse numeric port number
112940cb5e5dSvi117747 	 */
113040cb5e5dSvi117747 	if (SIP_URI_ISDIGIT(*scan)) {
113140cb5e5dSvi117747 		outurl->sip_uri_port = *scan - '0';
113240cb5e5dSvi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
113340cb5e5dSvi117747 		    outurl->sip_uri_port =
113440cb5e5dSvi117747 			outurl->sip_uri_port * 10 + (*scan - '0');
113540cb5e5dSvi117747 			if (outurl->sip_uri_port > 0xffff) {
113640cb5e5dSvi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PORT;
113740cb5e5dSvi117747 				outurl->sip_uri_port = 0;
113840cb5e5dSvi117747 				break;
113940cb5e5dSvi117747 			}
114040cb5e5dSvi117747 		}
114140cb5e5dSvi117747 	}
114240cb5e5dSvi117747 	if (scan < uend) {
114340cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
114440cb5e5dSvi117747 		outurl->sip_uri_port = 0;
114540cb5e5dSvi117747 	}
114640cb5e5dSvi117747 }
114740cb5e5dSvi117747 
114840cb5e5dSvi117747 /*
114940cb5e5dSvi117747  * parse an IPv4 address
115040cb5e5dSvi117747  *    1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
115140cb5e5dSvi117747  *  advances pscan to end of IPv4 address, or after last "." that was
115240cb5e5dSvi117747  *  a valid IPv4 or domain name.
115340cb5e5dSvi117747  * returns 1 if ipv4 found, 0 otherwise
115440cb5e5dSvi117747  */
115540cb5e5dSvi117747 static int
115640cb5e5dSvi117747 sip_uri_parse_ipv4(char *scan, char *uend)
115740cb5e5dSvi117747 {
115840cb5e5dSvi117747 	int	j = 0;
115940cb5e5dSvi117747 	int	val = 0;
116040cb5e5dSvi117747 
116140cb5e5dSvi117747 	for (j = 0; j < 4; ++j) {
116240cb5e5dSvi117747 		if (!SIP_URI_ISDIGIT(*scan))
116340cb5e5dSvi117747 			break;
116440cb5e5dSvi117747 		val = *scan - '0';
116540cb5e5dSvi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
116640cb5e5dSvi117747 			val = val * 10 + (*scan - '0');
116740cb5e5dSvi117747 			if (val > 255)
116840cb5e5dSvi117747 				return (0);
116940cb5e5dSvi117747 		}
117040cb5e5dSvi117747 		if (j < 3) {
117140cb5e5dSvi117747 			if (*scan != '.')
117240cb5e5dSvi117747 				break;
117340cb5e5dSvi117747 			++scan;
117440cb5e5dSvi117747 		}
117540cb5e5dSvi117747 	}
117640cb5e5dSvi117747 
117740cb5e5dSvi117747 	if (j == 4 && scan == uend)
117840cb5e5dSvi117747 		return (1);
117940cb5e5dSvi117747 
118040cb5e5dSvi117747 	return (0);
118140cb5e5dSvi117747 }
118240cb5e5dSvi117747 
118340cb5e5dSvi117747 /*
118440cb5e5dSvi117747  * parse an IPv6 address
118540cb5e5dSvi117747  *  IPv6address = hexpart [ ":" IPv4address ]
118640cb5e5dSvi117747  *  IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
118740cb5e5dSvi117747  *  hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
118840cb5e5dSvi117747  *  hexseq  = hex4 *( ":" hex4)
118940cb5e5dSvi117747  *  hex4    = 1*4HEXDIG
119040cb5e5dSvi117747  *  if not found, leaves pscan unchanged, otherwise advances to end
119140cb5e5dSvi117747  *  returns 1 if valid,
119240cb5e5dSvi117747  *  0 if invalid
119340cb5e5dSvi117747  */
119440cb5e5dSvi117747 static int
119540cb5e5dSvi117747 sip_uri_parse_ipv6(char *scan, char *uend)
119640cb5e5dSvi117747 {
119740cb5e5dSvi117747 	char		*mark;
119840cb5e5dSvi117747 	unsigned	j = 0;			/* index for addr */
119940cb5e5dSvi117747 	unsigned	val = 0;		/* hex value */
120040cb5e5dSvi117747 	int		zpad = 0;		/* index of :: delimiter */
120140cb5e5dSvi117747 
120240cb5e5dSvi117747 	if (*scan != '[')
120340cb5e5dSvi117747 		return (0);
120440cb5e5dSvi117747 	++scan;
120540cb5e5dSvi117747 	j = 0;
120640cb5e5dSvi117747 
120740cb5e5dSvi117747 	/*
120840cb5e5dSvi117747 	 * check for leading "::", set zpad to the position of the "::"
120940cb5e5dSvi117747 	 */
121040cb5e5dSvi117747 	if (scan + 1 < uend && scan[0] == ':' && scan[1] == ':') {
121140cb5e5dSvi117747 		zpad = 0;
121240cb5e5dSvi117747 		scan += 2;
121340cb5e5dSvi117747 	} else {
121440cb5e5dSvi117747 		zpad = -1;
121540cb5e5dSvi117747 	}
121640cb5e5dSvi117747 
121740cb5e5dSvi117747 	/*
121840cb5e5dSvi117747 	 * loop through up to 16 bytes of IPv6 address
121940cb5e5dSvi117747 	 */
122040cb5e5dSvi117747 	while (scan < uend && j < 15) {
122140cb5e5dSvi117747 		if (!SIP_URI_ISHEX(*scan))
122240cb5e5dSvi117747 			break;
122340cb5e5dSvi117747 		mark = scan;
122440cb5e5dSvi117747 		val = SIP_URI_HEXVAL(*scan);
122540cb5e5dSvi117747 		while (++scan < uend && SIP_URI_ISHEX(*scan)) {
122640cb5e5dSvi117747 			val = val * 16 + SIP_URI_HEXVAL(*scan);
122740cb5e5dSvi117747 			if (val > 0xffff)
122840cb5e5dSvi117747 				return (0);
122940cb5e5dSvi117747 		}
123040cb5e5dSvi117747 
123140cb5e5dSvi117747 		/*
123240cb5e5dSvi117747 		 * always require a delimiter or ]
123340cb5e5dSvi117747 		 */
123440cb5e5dSvi117747 		if (scan == uend)
123540cb5e5dSvi117747 			return (0);
123640cb5e5dSvi117747 
123740cb5e5dSvi117747 		if (*scan == '.' && (j == 12 || (zpad != -1 && j < 12)) &&
123840cb5e5dSvi117747 		    mark < uend && sip_uri_parse_ipv4(mark, uend - 1) &&
123940cb5e5dSvi117747 		    *(uend - 1) == ']') {
124040cb5e5dSvi117747 			mark = uend - 1;
124140cb5e5dSvi117747 			j += 4;
124240cb5e5dSvi117747 			scan = mark + 1;
124340cb5e5dSvi117747 			break;
124440cb5e5dSvi117747 		}
124540cb5e5dSvi117747 
124640cb5e5dSvi117747 		/*
124740cb5e5dSvi117747 		 * set address
124840cb5e5dSvi117747 		 */
124940cb5e5dSvi117747 		j += 2;
125040cb5e5dSvi117747 
125140cb5e5dSvi117747 		/*
125240cb5e5dSvi117747 		 * check for delimiter or ]
125340cb5e5dSvi117747 		 */
125440cb5e5dSvi117747 		if (*scan == ':') {
125540cb5e5dSvi117747 			/*
125640cb5e5dSvi117747 			 * found ":" delimiter, check for "::"
125740cb5e5dSvi117747 			 */
125840cb5e5dSvi117747 			if (++scan < uend && *scan == ':') {
125940cb5e5dSvi117747 				if (zpad != -1)
126040cb5e5dSvi117747 					return (0);
126140cb5e5dSvi117747 				zpad = j;
126240cb5e5dSvi117747 				if (++scan < uend && *scan == ']') {
126340cb5e5dSvi117747 					++scan;
126440cb5e5dSvi117747 					break;
126540cb5e5dSvi117747 				}
126640cb5e5dSvi117747 			}
126740cb5e5dSvi117747 		} else if (*scan == ']' && (j == 16 || zpad != -1)) {
126840cb5e5dSvi117747 			++scan;
126940cb5e5dSvi117747 			break;
127040cb5e5dSvi117747 		} else {
127140cb5e5dSvi117747 			/*
127240cb5e5dSvi117747 			 * not a valid delimiter
127340cb5e5dSvi117747 			 */
127440cb5e5dSvi117747 			return (0);
127540cb5e5dSvi117747 		}
127640cb5e5dSvi117747 	}
127740cb5e5dSvi117747 	if (zpad == -1 && j < 16)
127840cb5e5dSvi117747 		return (0);
127940cb5e5dSvi117747 	if (zpad != -1) {
128040cb5e5dSvi117747 		if (j > 15)
128140cb5e5dSvi117747 			return (0);
128240cb5e5dSvi117747 	}
128340cb5e5dSvi117747 
128440cb5e5dSvi117747 	if (scan == uend)
128540cb5e5dSvi117747 		return (1);
128640cb5e5dSvi117747 
128740cb5e5dSvi117747 	return (0);
128840cb5e5dSvi117747 }
128940cb5e5dSvi117747 
129040cb5e5dSvi117747 /*
129140cb5e5dSvi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
129240cb5e5dSvi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
129340cb5e5dSvi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
129440cb5e5dSvi117747  */
129540cb5e5dSvi117747 static int
129640cb5e5dSvi117747 sip_uri_parse_hostname(char *scan, char *uend)
129740cb5e5dSvi117747 {
129840cb5e5dSvi117747 	int	sawalpha = 0;
129940cb5e5dSvi117747 
130040cb5e5dSvi117747 	if (scan < uend && SIP_URI_ISALNUM(*scan)) {
130140cb5e5dSvi117747 		do {
130240cb5e5dSvi117747 			sawalpha = SIP_URI_ISALPHA(*scan);
130340cb5e5dSvi117747 			while (SIP_URI_ISHOST(*scan))
130440cb5e5dSvi117747 				++scan;
130540cb5e5dSvi117747 			if (*scan != '.')
130640cb5e5dSvi117747 				break;
130740cb5e5dSvi117747 			++scan;
130840cb5e5dSvi117747 		} while (scan < uend && SIP_URI_ISALNUM(*scan));
130940cb5e5dSvi117747 	}
131040cb5e5dSvi117747 
131140cb5e5dSvi117747 	if (sawalpha && scan == uend)
131240cb5e5dSvi117747 		return (1);
131340cb5e5dSvi117747 	return (0);
131440cb5e5dSvi117747 }
131540cb5e5dSvi117747 
131640cb5e5dSvi117747 
131740cb5e5dSvi117747 /*
131840cb5e5dSvi117747  * parse the network path portion of a full URL
131940cb5e5dSvi117747  */
132040cb5e5dSvi117747 static void
132140cb5e5dSvi117747 sip_uri_parse_netpath(_sip_uri_t *outurl, char **pscan, char *uend,
132240cb5e5dSvi117747     boolean_t issip)
132340cb5e5dSvi117747 {
132440cb5e5dSvi117747 	char	*mark = (char *)0;
132540cb5e5dSvi117747 	char	*mark2 = (char *)0;
132640cb5e5dSvi117747 	char	*scan = *pscan;
132740cb5e5dSvi117747 	int	gothost = 0;
132840cb5e5dSvi117747 
132940cb5e5dSvi117747 	/*
133040cb5e5dSvi117747 	 * look for the first high-level delimiter
133140cb5e5dSvi117747 	 */
133240cb5e5dSvi117747 	mark = scan;
133340cb5e5dSvi117747 	while (scan < uend && *scan != '@')
133440cb5e5dSvi117747 		++scan;
133540cb5e5dSvi117747 	/*
133640cb5e5dSvi117747 	 * handle userinfo section of URL
133740cb5e5dSvi117747 	 */
133840cb5e5dSvi117747 	if (scan < uend && *scan == '@') {
133940cb5e5dSvi117747 		/*
134040cb5e5dSvi117747 		 * parse user
134140cb5e5dSvi117747 		 */
134240cb5e5dSvi117747 		mark2 = mark;
134340cb5e5dSvi117747 		while (mark < scan && *mark != ':')
134440cb5e5dSvi117747 			++mark;
134540cb5e5dSvi117747 		sip_uri_parse_user(outurl, mark2, mark);
134640cb5e5dSvi117747 		/*
134740cb5e5dSvi117747 		 * parse password
134840cb5e5dSvi117747 		 */
134940cb5e5dSvi117747 		if (*mark == ':')
135040cb5e5dSvi117747 			sip_uri_parse_password(outurl, mark, scan);
135140cb5e5dSvi117747 		mark = ++scan;
135240cb5e5dSvi117747 	}
135340cb5e5dSvi117747 
135440cb5e5dSvi117747 	scan = mark;
135540cb5e5dSvi117747 	if (scan < uend && *scan == '[') {	/* look for an IPv6 address */
135640cb5e5dSvi117747 		while (scan < uend && *scan != ']')
135740cb5e5dSvi117747 			++scan;
135840cb5e5dSvi117747 		if (scan < uend) {
135940cb5e5dSvi117747 			++scan;
136040cb5e5dSvi117747 			if (sip_uri_parse_ipv6(mark, scan))
136140cb5e5dSvi117747 				gothost = 1;
136240cb5e5dSvi117747 		}
136340cb5e5dSvi117747 	} else {
136440cb5e5dSvi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPHDELIM(*scan)) ||
136540cb5e5dSvi117747 		    (!issip && !SIP_URI_ISABSHDELIM(*scan)))) {
136640cb5e5dSvi117747 			++scan;
136740cb5e5dSvi117747 		}
136840cb5e5dSvi117747 
136940cb5e5dSvi117747 		/*
137040cb5e5dSvi117747 		 * look for an IPv4 address
137140cb5e5dSvi117747 		 */
137240cb5e5dSvi117747 		if (mark < scan && SIP_URI_ISDIGIT(*mark) &&
137340cb5e5dSvi117747 		    sip_uri_parse_ipv4(mark, scan)) {
137440cb5e5dSvi117747 			gothost = 1;
137540cb5e5dSvi117747 		}
137640cb5e5dSvi117747 
137740cb5e5dSvi117747 		/*
137840cb5e5dSvi117747 		 * look for a valid host name
137940cb5e5dSvi117747 		 */
138040cb5e5dSvi117747 		if (!gothost && mark < scan &&
138140cb5e5dSvi117747 		    sip_uri_parse_hostname(mark, scan)) {
138240cb5e5dSvi117747 			gothost = 1;
138340cb5e5dSvi117747 		}
138440cb5e5dSvi117747 	}
138540cb5e5dSvi117747 	/*
138640cb5e5dSvi117747 	 * handle invalid host name
138740cb5e5dSvi117747 	 */
138840cb5e5dSvi117747 	if (!gothost)
138940cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HOST;
139040cb5e5dSvi117747 	/*
139140cb5e5dSvi117747 	 * save host name
139240cb5e5dSvi117747 	 */
139340cb5e5dSvi117747 	outurl->sip_uri_host.sip_str_ptr = mark;
139440cb5e5dSvi117747 	outurl->sip_uri_host.sip_str_len = scan - mark;
139540cb5e5dSvi117747 
139640cb5e5dSvi117747 	mark = scan;
139740cb5e5dSvi117747 	/*
139840cb5e5dSvi117747 	 * parse the port number
139940cb5e5dSvi117747 	 */
140040cb5e5dSvi117747 	if (scan < uend && *scan == ':') {
140140cb5e5dSvi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPDELIM(*scan)) ||
140240cb5e5dSvi117747 		    (!issip && !SIP_URI_ISABSDELIM(*scan)))) {
140340cb5e5dSvi117747 			++scan;
140440cb5e5dSvi117747 		}
140540cb5e5dSvi117747 		sip_uri_parse_port(outurl, mark, scan);
140640cb5e5dSvi117747 	}
140740cb5e5dSvi117747 
140840cb5e5dSvi117747 	/*
140940cb5e5dSvi117747 	 * set return pointer
141040cb5e5dSvi117747 	 */
141140cb5e5dSvi117747 	*pscan = scan;
141240cb5e5dSvi117747 }
141340cb5e5dSvi117747 
141440cb5e5dSvi117747 /*
141540cb5e5dSvi117747  * parse a URL
141640cb5e5dSvi117747  * URL = SIP-URI / SIPS-URI / absoluteURI
141740cb5e5dSvi117747  */
141840cb5e5dSvi117747 void
141940cb5e5dSvi117747 sip_uri_parse_it(_sip_uri_t *outurl, sip_str_t *uri_str)
142040cb5e5dSvi117747 {
142140cb5e5dSvi117747 	char 		*mark;
142240cb5e5dSvi117747 	char		*scan;
142340cb5e5dSvi117747 	char		*uend;
142440cb5e5dSvi117747 	char		*str = uri_str->sip_str_ptr;
142540cb5e5dSvi117747 	unsigned	urlen = uri_str->sip_str_len;
142640cb5e5dSvi117747 
142740cb5e5dSvi117747 	/*
142840cb5e5dSvi117747 	 * reset output parameters
142940cb5e5dSvi117747 	 */
143040cb5e5dSvi117747 	(void) memset(outurl, 0, sizeof (sip_uri_t));
143140cb5e5dSvi117747 
143240cb5e5dSvi117747 	/*
143340cb5e5dSvi117747 	 * strip enclosing angle brackets
143440cb5e5dSvi117747 	 */
143540cb5e5dSvi117747 	if (urlen > 1 && str[0] == '<' && str[urlen-1] == '>') {
143640cb5e5dSvi117747 		urlen -= 2;
143740cb5e5dSvi117747 		++str;
143840cb5e5dSvi117747 	}
143940cb5e5dSvi117747 	uend = str + urlen;
144040cb5e5dSvi117747 
144140cb5e5dSvi117747 	/*
144240cb5e5dSvi117747 	 * strip off space prefix and trailing spaces
144340cb5e5dSvi117747 	 */
144440cb5e5dSvi117747 	while (str < uend && isspace(*str)) {
144540cb5e5dSvi117747 		++str;
144640cb5e5dSvi117747 		--urlen;
144740cb5e5dSvi117747 	}
144840cb5e5dSvi117747 	while (str < uend && isspace(*(uend - 1))) {
144940cb5e5dSvi117747 		--uend;
145040cb5e5dSvi117747 		--urlen;
145140cb5e5dSvi117747 	}
145240cb5e5dSvi117747 
145340cb5e5dSvi117747 	/*
145440cb5e5dSvi117747 	 * strip off "URL:" prefix
145540cb5e5dSvi117747 	 */
145640cb5e5dSvi117747 	if (urlen > 4 && sip_uri_url_casecmp(str, "URL:", 4) == 0) {
145740cb5e5dSvi117747 		str += 4;
145840cb5e5dSvi117747 		urlen -= 4;
145940cb5e5dSvi117747 	}
146040cb5e5dSvi117747 
146140cb5e5dSvi117747 	/*
146240cb5e5dSvi117747 	 * parse the scheme name
146340cb5e5dSvi117747 	 */
146440cb5e5dSvi117747 	mark = scan = str;
146540cb5e5dSvi117747 	while (scan < uend && *scan != ':')
146640cb5e5dSvi117747 		++scan;
146740cb5e5dSvi117747 	if (scan == uend || !sip_uri_parse_scheme(outurl, mark, scan)) {
146840cb5e5dSvi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
146940cb5e5dSvi117747 		return;
147040cb5e5dSvi117747 	}
147140cb5e5dSvi117747 
147240cb5e5dSvi117747 	if ((outurl->sip_uri_scheme.sip_str_len == SIP_SCHEME_LEN &&
147340cb5e5dSvi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIP_SCHEME,
147440cb5e5dSvi117747 	    SIP_SCHEME_LEN)) ||
147540cb5e5dSvi117747 	    (outurl->sip_uri_scheme.sip_str_len == SIPS_SCHEME_LEN &&
147640cb5e5dSvi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIPS_SCHEME,
147740cb5e5dSvi117747 	    SIPS_SCHEME_LEN))) {
147840cb5e5dSvi117747 		outurl->sip_uri_issip = B_TRUE;
147940cb5e5dSvi117747 	} else {
148040cb5e5dSvi117747 		outurl->sip_uri_issip = B_FALSE;
148140cb5e5dSvi117747 	}
148240cb5e5dSvi117747 	++scan; /* skip ':' */
148340cb5e5dSvi117747 
148440cb5e5dSvi117747 	if (outurl->sip_uri_issip) {
148540cb5e5dSvi117747 		/*
148640cb5e5dSvi117747 		 * parse SIP URL
148740cb5e5dSvi117747 		 */
148840cb5e5dSvi117747 		sip_uri_parse_netpath(outurl, &scan, uend, B_TRUE);
148940cb5e5dSvi117747 
149040cb5e5dSvi117747 		/*
149140cb5e5dSvi117747 		 * parse parameters
149240cb5e5dSvi117747 		 */
149340cb5e5dSvi117747 		if (scan < uend && *scan == ';') {
149440cb5e5dSvi117747 			mark = scan;
149540cb5e5dSvi117747 			while (scan < uend && *scan != '?')
149640cb5e5dSvi117747 				++scan;
149740cb5e5dSvi117747 			sip_uri_parse_params(outurl, mark, scan);
149840cb5e5dSvi117747 		}
149940cb5e5dSvi117747 
150040cb5e5dSvi117747 		/*
150140cb5e5dSvi117747 		 * parse headers
150240cb5e5dSvi117747 		 */
150340cb5e5dSvi117747 		if (scan < uend && *scan == '?')
150440cb5e5dSvi117747 			sip_uri_parse_headers(outurl, scan, uend);
150540cb5e5dSvi117747 	} else if (scan < uend && scan[0] == '/') {	 /* parse absoluteURL */
150640cb5e5dSvi117747 		++scan;
150740cb5e5dSvi117747 		/*
150840cb5e5dSvi117747 		 * parse authority
150940cb5e5dSvi117747 		 * authority	= srvr / reg-name
151040cb5e5dSvi117747 		 * srvr		= [ [ userinfo "@" ] hostport ]
151140cb5e5dSvi117747 		 * reg-name	= 1*(unreserved / escaped / "$" / ","
151240cb5e5dSvi117747 		 *			/ ";" / ":" / "@" / "&" / "=" / "+")
151340cb5e5dSvi117747 		 */
151440cb5e5dSvi117747 		if (scan < uend && *scan == '/') {
151540cb5e5dSvi117747 			++scan;
151640cb5e5dSvi117747 			mark = scan;
151740cb5e5dSvi117747 			/*
151840cb5e5dSvi117747 			 * take authority as srvr
151940cb5e5dSvi117747 			 */
152040cb5e5dSvi117747 			sip_uri_parse_netpath(outurl, &scan, uend, B_FALSE);
152140cb5e5dSvi117747 
152240cb5e5dSvi117747 			/*
152340cb5e5dSvi117747 			 * if srvr failed, take it as reg-name
152440cb5e5dSvi117747 			 * parse reg-name
152540cb5e5dSvi117747 			 */
152640cb5e5dSvi117747 			if (outurl->sip_uri_errflags & SIP_URIERR_USER ||
152740cb5e5dSvi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PASS ||
152840cb5e5dSvi117747 			    outurl->sip_uri_errflags & SIP_URIERR_HOST ||
152940cb5e5dSvi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PORT) {
153040cb5e5dSvi117747 				scan = mark;
153140cb5e5dSvi117747 				while (scan < uend && *scan != '/' &&
153240cb5e5dSvi117747 					*scan != '?') {
153340cb5e5dSvi117747 					++scan;
153440cb5e5dSvi117747 				}
153540cb5e5dSvi117747 				sip_uri_parse_abs_regname(outurl, mark, scan);
153640cb5e5dSvi117747 				if (!(outurl->sip_uri_errflags &
153740cb5e5dSvi117747 				    SIP_URIERR_REGNAME)) {
153840cb5e5dSvi117747 					/*
153940cb5e5dSvi117747 					 * remove error info of user,
154040cb5e5dSvi117747 					 * password, host, port
154140cb5e5dSvi117747 					 */
154240cb5e5dSvi117747 					outurl->sip_uri_user.sip_str_ptr = NULL;
154340cb5e5dSvi117747 					outurl->sip_uri_user.sip_str_len = 0;
154440cb5e5dSvi117747 					outurl->sip_uri_errflags &=
154540cb5e5dSvi117747 					    ~SIP_URIERR_USER;
154640cb5e5dSvi117747 					outurl->sip_uri_password.sip_str_ptr =
154740cb5e5dSvi117747 					    NULL;
154840cb5e5dSvi117747 					outurl->sip_uri_password.sip_str_len =
154940cb5e5dSvi117747 					    0;
155040cb5e5dSvi117747 					outurl->sip_uri_errflags &=
155140cb5e5dSvi117747 					    ~SIP_URIERR_PASS;
155240cb5e5dSvi117747 					outurl->sip_uri_host.sip_str_ptr = NULL;
155340cb5e5dSvi117747 					outurl->sip_uri_host.sip_str_len = 0;
155440cb5e5dSvi117747 					outurl->sip_uri_errflags &=
155540cb5e5dSvi117747 					    ~SIP_URIERR_HOST;
155640cb5e5dSvi117747 					outurl->sip_uri_port = 0;
155740cb5e5dSvi117747 					outurl->sip_uri_errflags &=
155840cb5e5dSvi117747 					    ~SIP_URIERR_PORT;
155940cb5e5dSvi117747 				}
156040cb5e5dSvi117747 			}
156140cb5e5dSvi117747 		} else {
156240cb5e5dSvi117747 			/*
156340cb5e5dSvi117747 			 * there is no net-path
156440cb5e5dSvi117747 			 */
156540cb5e5dSvi117747 			--scan;
156640cb5e5dSvi117747 		}
156740cb5e5dSvi117747 		/*
156840cb5e5dSvi117747 		 * parse abs-path
156940cb5e5dSvi117747 		 */
157040cb5e5dSvi117747 		if (scan < uend && *scan == '/') {
157140cb5e5dSvi117747 			mark = scan;
157240cb5e5dSvi117747 			while (scan < uend && *scan != '?')
157340cb5e5dSvi117747 				++scan;
157440cb5e5dSvi117747 			sip_uri_parse_abs_path(outurl, mark, scan);
157540cb5e5dSvi117747 		}
157640cb5e5dSvi117747 
157740cb5e5dSvi117747 		/*
157840cb5e5dSvi117747 		 * parse query
157940cb5e5dSvi117747 		 */
158040cb5e5dSvi117747 		if (scan < uend && *scan == '?')
158140cb5e5dSvi117747 			sip_uri_parse_abs_query(outurl, scan, uend);
158240cb5e5dSvi117747 	} else {
158340cb5e5dSvi117747 		/*
158440cb5e5dSvi117747 		 * parse opaque-part
158540cb5e5dSvi117747 		 */
158640cb5e5dSvi117747 		sip_uri_parse_abs_opaque(outurl, scan, uend);
158740cb5e5dSvi117747 	}
158840cb5e5dSvi117747 }
1589