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