xref: /onnv-gate/usr/src/lib/libsip/common/sip_parse_uri.c (revision 3439:0302bfe973fe)
12882Svi117747 /*
22882Svi117747  * CDDL HEADER START
32882Svi117747  *
42882Svi117747  * The contents of this file are subject to the terms of the
52882Svi117747  * Common Development and Distribution License (the "License").
62882Svi117747  * You may not use this file except in compliance with the License.
72882Svi117747  *
82882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92882Svi117747  * or http://www.opensolaris.org/os/licensing.
102882Svi117747  * See the License for the specific language governing permissions
112882Svi117747  * and limitations under the License.
122882Svi117747  *
132882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
142882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
162882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
172882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
182882Svi117747  *
192882Svi117747  * CDDL HEADER END
202882Svi117747  */
212882Svi117747 
222882Svi117747 /*
23*3439Svi117747  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
242882Svi117747  * Use is subject to license terms.
252882Svi117747  */
262882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
272882Svi117747 
28*3439Svi117747 #include <ctype.h>
292882Svi117747 #include <stdlib.h>
302882Svi117747 #include <string.h>
312882Svi117747 
322882Svi117747 #include "sip_parse_uri.h"
332882Svi117747 
342882Svi117747 /*
352882Svi117747  * SIP-URI          =  "sip:" [ userinfo ] hostport uri-parameters [ headers ]
362882Svi117747  * SIPS-URI         =  "sips:" [ userinfo ] hostport uri-parameters [ headers ]
372882Svi117747  * userinfo         =  ( user / telephone-subscriber ) [ ":" password ] "@"
382882Svi117747  * user             =  1*( unreserved / escaped / user-unreserved )
392882Svi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
402882Svi117747  * password         =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
412882Svi117747  * hostport         =  host [ ":" port ]
422882Svi117747  * host             =  hostname / IPv4address / IPv6reference
432882Svi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
442882Svi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
452882Svi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
462882Svi117747  * IPv4address    =  1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
472882Svi117747  * IPv6reference  =  "[" IPv6address "]"
482882Svi117747  * IPv6address    =  hexpart [ ":" IPv4address ]
492882Svi117747  * hexpart        =  hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
502882Svi117747  * hexseq         =  hex4 *( ":" hex4)
512882Svi117747  * hex4           =  1*4HEXDIG
522882Svi117747  * port           =  1*DIGIT
532882Svi117747  *
542882Svi117747  * The BNF for telephone-subscriber can be found in RFC 2806 [9].  Note,
552882Svi117747  * however, that any characters allowed there that are not allowed in
562882Svi117747  * the user part of the SIP URI MUST be escaped.
572882Svi117747  *
582882Svi117747  * uri-parameters    =  *( ";" uri-parameter)
592882Svi117747  * uri-parameter     =  transport-param / user-param / method-param
602882Svi117747  *                      / ttl-param / maddr-param / lr-param / other-param
612882Svi117747  * transport-param   =  "transport="( "udp" / "tcp" / "sctp" / "tls"
622882Svi117747  *                     / other-transport)
632882Svi117747  * other-transport   =  token
642882Svi117747  * user-param        =  "user=" ( "phone" / "ip" / other-user)
652882Svi117747  * other-user        =  token
662882Svi117747  * method-param      =  "method=" Method
672882Svi117747  * ttl-param         =  "ttl=" ttl
682882Svi117747  * maddr-param       =  "maddr=" host
692882Svi117747  * lr-param          =  "lr"
702882Svi117747  * other-param       =  pname [ "=" pvalue ]
712882Svi117747  * pname             =  1*paramchar
722882Svi117747  * pvalue            =  1*paramchar
732882Svi117747  * paramchar         =  param-unreserved / unreserved / escaped
742882Svi117747  * param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
752882Svi117747  * headers         =  "?" header *( "&" header )
762882Svi117747  * header          =  hname "=" hvalue
772882Svi117747  * hname           =  1*( hnv-unreserved / unreserved / escaped )
782882Svi117747  * hvalue          =  *( hnv-unreserved / unreserved / escaped )
792882Svi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
802882Svi117747  *
812882Svi117747  */
822882Svi117747 
832882Svi117747 #define	SIP_URI_MSG_BUF_SZ	100
842882Svi117747 
852882Svi117747 #define	SIP_URI_ISHEX(c)					\
862882Svi117747 	(((int)(c) >= 0x30 && (int)(c) <= 0x39) || 	\
872882Svi117747 	((int)(c) >= 0x41 && (int)(c) <= 0x46) || 	\
882882Svi117747 	((int)(c) >= 0x61 && (int)(c) <= 0x66))
892882Svi117747 
902882Svi117747 #define	SIP_URI_ISURLESCAPE(scan, end)			\
912882Svi117747 	((scan) + 2 < (end) && (scan)[0] == '%' && 	\
922882Svi117747 	SIP_URI_ISHEX((scan)[1]) && SIP_URI_ISHEX((scan[2])))
932882Svi117747 
942882Svi117747 /*
952882Svi117747  * URL character classes
962882Svi117747  *  mark	- _ . ! ~ * ' ()
972882Svi117747  *  reserved	; / ? : @ & = + $ ,    also [] for IPv6
982882Svi117747  *  unreserved	alphanum mark
992882Svi117747  *  pchar	: @ & = + $ , unreserved
1002882Svi117747  *  userinfo	; : & = + $ , unreserved escaped
1012882Svi117747  *  relsegment	; @ & = + $ , unreserved escaped
1022882Svi117747  *  reg_name	; : @ & = + $ , unreserved escaped
1032882Svi117747  *  token	- _ . ! ~ * ' %  + `
1042882Svi117747  *  param-unreserved  [ ] / : + $ &
1052882Svi117747  *  hnv-unreserved    [ ] / : + $ ?
1062882Svi117747  */
1072882Svi117747 #define	SIP_URI_ALPHA_BIT		0x0001
1082882Svi117747 #define	SIP_URI_DIGIT_BIT		0x0002
1092882Svi117747 #define	SIP_URI_ALNUM_BITS		0x0003
1102882Svi117747 #define	SIP_URI_SCHEME_BIT		0x0004	/* for - + . */
1112882Svi117747 #define	SIP_URI_TOKEN_BIT		0x0008	/* for - _ . ! ~ * ' % + ` */
1122882Svi117747 #define	SIP_URI_QUEST_BIT		0x0010	/* for ? */
1132882Svi117747 #define	SIP_URI_AT_BIT			0x0020	/* for @ */
1142882Svi117747 #define	SIP_URI_COLON_BIT		0x0040	/* for : */
1152882Svi117747 #define	SIP_URI_SEMI_BIT		0x0080	/* for ; */
1162882Svi117747 #define	SIP_URI_DASH_BIT		0x0100	/* for - */
1172882Svi117747 #define	SIP_URI_MARK_BIT		0x0200	/* for - _ . ! ~ * ' ( ) */
1182882Svi117747 #define	SIP_URI_AND_BIT			0x0400	/* for & */
1192882Svi117747 #define	SIP_URI_PHCOMM_BIT		0x0800	/* for [ ] / : + $ */
1202882Svi117747 #define	SIP_URI_OTHER_BIT		0x1000	/* for = + $ , */
1212882Svi117747 #define	SIP_URI_SLASH_BIT		0x2000	/* for / */
1222882Svi117747 #define	SIP_URI_VISUALSEP_BIT		0x4000	/* for -.() */
1232882Svi117747 #define	SIP_URI_DTMFURI_DIGIT_BIT	0x8000	/* for *ABCD */
1242882Svi117747 
1252882Svi117747 #define	a 			SIP_URI_ALPHA_BIT
1262882Svi117747 #define	d 			SIP_URI_DIGIT_BIT
1272882Svi117747 #define	s 			SIP_URI_SCHEME_BIT
1282882Svi117747 #define	t 			SIP_URI_TOKEN_BIT
1292882Svi117747 #define	q 			SIP_URI_QUEST_BIT
1302882Svi117747 #define	m 			SIP_URI_AT_BIT
1312882Svi117747 #define	c 			SIP_URI_COLON_BIT
1322882Svi117747 #define	i 			SIP_URI_SEMI_BIT
1332882Svi117747 #define	h 			SIP_URI_DASH_BIT
1342882Svi117747 #define	k 			SIP_URI_MARK_BIT
1352882Svi117747 #define	n 			SIP_URI_AND_BIT
1362882Svi117747 #define	o 			SIP_URI_PHCOMM_BIT
1372882Svi117747 #define	r 			SIP_URI_OTHER_BIT
1382882Svi117747 #define	l 			SIP_URI_SLASH_BIT
1392882Svi117747 #define	v 			SIP_URI_VISUALSEP_BIT
1402882Svi117747 #define	f 			SIP_URI_DTMFURI_DIGIT_BIT
1412882Svi117747 
1422882Svi117747 static const unsigned short sip_uri_table[256] = {
1432882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1442882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1452882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1462882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1472882Svi117747 	0,	t|k,	0,	0,	o|r,	t,	n,	t|k,
1482882Svi117747 	k|v,	k|v,	t|k|f, s|t|r|o,	r,  h|s|t|k|v, s|t|k|v,	o|l,
1492882Svi117747 	d,	d,	d,	d,	d,	d,	d,	d,
1502882Svi117747 	d,	d,	c|o,	i,	0,	r,	0,	q,
1512882Svi117747 	m,	a|f,	a|f,	a|f,	a|f,	a,	a,	a,
1522882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
1532882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
1542882Svi117747 	a,	a,	a,	o,	0,	o,	0,	t|k,
1552882Svi117747 	t,	a,	a,	a,	a,	a,	a,	a,
1562882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
1572882Svi117747 	a,	a,	a,	a,	a,	a,	a,	a,
1582882Svi117747 	a,	a,	a,	0,	0,	0,	t|k,	0,
1592882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1602882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1612882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1622882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1632882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1642882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1652882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1662882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1672882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1682882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1692882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1702882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1712882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1722882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1732882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1742882Svi117747 	0,	0,	0,	0,	0,	0,	0,	0,
1752882Svi117747 };
1762882Svi117747 
1772882Svi117747 #undef	a
1782882Svi117747 #undef	d
1792882Svi117747 #undef	s
1802882Svi117747 #undef	t
1812882Svi117747 #undef	q
1822882Svi117747 #undef	m
1832882Svi117747 #undef	c
1842882Svi117747 #undef	i
1852882Svi117747 #undef	h
1862882Svi117747 #undef	k
1872882Svi117747 #undef	n
1882882Svi117747 #undef	o
1892882Svi117747 #undef	r
1902882Svi117747 #undef	l
1912882Svi117747 #undef	v
1922882Svi117747 #undef	f
1932882Svi117747 
1942882Svi117747 #define	SIP_URI_UT(c)			sip_uri_table[(unsigned char)(c)]
1952882Svi117747 #define	SIP_URI_ISALPHA(c)		(SIP_URI_UT(c) & SIP_URI_ALPHA_BIT)
1962882Svi117747 #define	SIP_URI_ISDIGIT(c)		(SIP_URI_UT(c) & SIP_URI_DIGIT_BIT)
1972882Svi117747 #define	SIP_URI_ISALNUM(c)		(SIP_URI_UT(c) & SIP_URI_ALNUM_BITS)
1982882Svi117747 #define	SIP_URI_ISSCHEME(c)		\
1992882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_SCHEME_BIT))
2002882Svi117747 #define	SIP_URI_ISTOKEN(c)		\
2012882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_TOKEN_BIT))
2022882Svi117747 #define	SIP_URI_ISSIPDELIM(c)		\
2032882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
2042882Svi117747 #define	SIP_URI_ISSIPHDELIM(c)					\
2052882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
2062882Svi117747 #define	SIP_URI_ISHOST(c)		\
2072882Svi117747 		(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_DASH_BIT))
2082882Svi117747 #define	SIP_URI_ISUSER(c)						\
2092882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|		\
2102882Svi117747 	SIP_URI_QUEST_BIT|SIP_URI_SLASH_BIT|SIP_URI_AND_BIT))
2112882Svi117747 
2122882Svi117747 #define	SIP_URI_ISABSHDELIM(c)					\
2132882Svi117747 	(SIP_URI_UT(c) & \
2142882Svi117747 	(SIP_URI_SLASH_BIT|SIP_URI_COLON_BIT|SIP_URI_QUEST_BIT))
2152882Svi117747 #define	SIP_URI_ISABSDELIM(c)	\
2162882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_SLASH_BIT|SIP_URI_QUEST_BIT))
2172882Svi117747 #define	SIP_URI_ISUNRESERVED(c)	\
2182882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
2192882Svi117747 #define	SIP_URI_ISPARAM(c)						\
2202882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_AND_BIT|\
2212882Svi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
2222882Svi117747 #define	SIP_URI_ISHEADER(c)						\
2232882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_QUEST_BIT|\
2242882Svi117747 	SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
2252882Svi117747 #define	SIP_URI_ISOTHER(c)		(SIP_URI_UT(c) & SIP_URI_OTHER_BIT)
2262882Svi117747 #define	SIP_URI_ISRESERVED(c)					\
2272882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_SLASH_BIT|	\
2282882Svi117747 	SIP_URI_QUEST_BIT| SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
2292882Svi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
2302882Svi117747 #define	SIP_URI_ISPCHAR(c)	\
2312882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_AT_BIT|	\
2322882Svi117747 	SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
2332882Svi117747 #define	SIP_URI_ISREGNAME(c)					\
2342882Svi117747 	(SIP_URI_UT(c) & 	\
2352882Svi117747 	(SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|SIP_URI_COLON_BIT|	\
2362882Svi117747 	SIP_URI_AT_BIT|SIP_URI_AND_BIT))
2372882Svi117747 #define	SIP_URI_ISPHONEDIGIT(c)	\
2382882Svi117747 	(SIP_URI_UT(c) & (SIP_URI_DIGIT_BIT|SIP_URI_VISUALSEP_BIT))
2392882Svi117747 #define	SIP_URI_ISDTMFDIGIT(c)	(SIP_URI_UT(c) & SIP_URI_DTMFURI_DIGIT_BIT)
2402882Svi117747 
2412882Svi117747 static int  sip_uri_url_casecmp(const char *, const char *, unsigned);
2422882Svi117747 static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
2432882Svi117747 static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
2442882Svi117747 static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
2452882Svi117747 static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
2462882Svi117747 static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
2472882Svi117747 static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
2482882Svi117747 static int  sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
2492882Svi117747 static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
2502882Svi117747 static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
2512882Svi117747 static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
2522882Svi117747 static void sip_uri_parse_netpath(_sip_uri_t *, char **, char *, boolean_t);
2532882Svi117747 static int  sip_uri_parse_ipv6(char *, char *);
2542882Svi117747 static int  sip_uri_parse_ipv4(char *, char *);
2552882Svi117747 static int  sip_uri_parse_hostname(char *, char *);
2562882Svi117747 static int sip_uri_parse_tel(char *, char *);
2572882Svi117747 static int sip_uri_parse_tel_areaspe(char *, char *);
2582882Svi117747 static int sip_uri_parse_tel_servicepro(char *, char *);
2592882Svi117747 static int sip_uri_parse_tel_futureext(char *, char *);
2602882Svi117747 static int sip_uri_isTokenchar(char **, char *);
2612882Svi117747 static int sip_uri_isEscapedPound(char **, char *);
2622882Svi117747 static int sip_uri_hexVal(char *, char *);
2632882Svi117747 static int SIP_URI_HEXVAL(int);
2642882Svi117747 
2652882Svi117747 /*
2662882Svi117747  * get the hex value of a char
2672882Svi117747  */
2682882Svi117747 static int
SIP_URI_HEXVAL(int c)2692882Svi117747 SIP_URI_HEXVAL(int c)
2702882Svi117747 {
2712882Svi117747 	if (c >= 0x30 && c <= 0x39)
2722882Svi117747 		return (c - '0');
2732882Svi117747 	if (c >= 0x41 && c <= 0x46)
2742882Svi117747 		return (c - 'A' + 10);
2752882Svi117747 	if (c >= 0x61 && c <= 0x66)
2762882Svi117747 		return (c - 'a' + 10);
2772882Svi117747 	return (c);
2782882Svi117747 }
2792882Svi117747 
2802882Svi117747 /*
2812882Svi117747  * basic ASCII case-insensitive comparison
2822882Svi117747  */
2832882Svi117747 static int
sip_uri_url_casecmp(const char * str1,const char * str2,unsigned len)2842882Svi117747 sip_uri_url_casecmp(const char *str1, const char *str2, unsigned len)
2852882Svi117747 {
2862882Svi117747 	unsigned	j;
2872882Svi117747 
2882882Svi117747 	for (j = 0; j < len && tolower(str1[j]) == tolower(str2[j]) &&
2892882Svi117747 	    str1[j] != '\0'; ++j) {
2902882Svi117747 		;
2912882Svi117747 	}
2922882Svi117747 	return (j == len ? 0 : tolower(str2[j]) - tolower(str1[j]));
2932882Svi117747 }
2942882Svi117747 
2952882Svi117747 /*
2962882Svi117747  * telephone-subscriber  = global-phone-number / local-phone-number
2972882Svi117747  * Please refer to RFC 2806
2982882Svi117747  */
2992882Svi117747 static int
sip_uri_parse_tel(char * scan,char * uend)3002882Svi117747 sip_uri_parse_tel(char *scan, char *uend)
3012882Svi117747 {
3022882Svi117747 	char	*mark = (char *)0;
3032882Svi117747 	int	ret = 0;
3042882Svi117747 	int	isGlobal = 0;
3052882Svi117747 	int	quote = 0;
3062882Svi117747 
3072882Svi117747 	if (scan == uend)
3082882Svi117747 		return (0);
3092882Svi117747 	if (*scan == '+') {
3102882Svi117747 		++scan;
3112882Svi117747 		isGlobal = 1;
3122882Svi117747 	}
3132882Svi117747 	mark = scan;
3142882Svi117747 	if (isGlobal) {
3152882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
3162882Svi117747 			++scan;
3172882Svi117747 	} else {
3182882Svi117747 		while (scan < uend &&
3192882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
3202882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
3212882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
3222882Svi117747 		    *scan == 'p' || *scan == 'w')) {
3232882Svi117747 			++scan;
3242882Svi117747 		}
3252882Svi117747 	}
3262882Svi117747 	if (mark == scan || (scan < uend && *scan != ';'))
3272882Svi117747 		return (0);
3282882Svi117747 
3292882Svi117747 	/*
3302882Svi117747 	 * parse isdn-subaddress
3312882Svi117747 	 */
3322882Svi117747 	if (uend - scan > 6 && !sip_uri_url_casecmp(scan, ";isub=", 6)) {
3332882Svi117747 		scan += 6;
3342882Svi117747 		mark = scan;
3352882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
3362882Svi117747 			++scan;
3372882Svi117747 		if (mark == scan || (scan < uend && *scan != ';'))
3382882Svi117747 			return (0);
3392882Svi117747 	}
3402882Svi117747 
3412882Svi117747 	/*
3422882Svi117747 	 * parse post-dial
3432882Svi117747 	 */
3442882Svi117747 	if (uend - scan > 7 && !sip_uri_url_casecmp(scan, ";postd=", 7)) {
3452882Svi117747 		scan += 7;
3462882Svi117747 		mark = scan;
3472882Svi117747 		while (scan < uend &&
3482882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
3492882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
3502882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
3512882Svi117747 		    *scan == 'p' || *scan == 'w')) {
3522882Svi117747 			++scan;
3532882Svi117747 		}
3542882Svi117747 		if (mark == scan || (scan < uend && *scan != ';'))
3552882Svi117747 			return (0);
3562882Svi117747 	}
3572882Svi117747 
3582882Svi117747 	if (!isGlobal) {
3592882Svi117747 		/*
3602882Svi117747 		 * parse area-specifier
3612882Svi117747 		 */
3622882Svi117747 		if (uend - scan > 15 &&
3632882Svi117747 		    !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
3642882Svi117747 			scan += 15;
3652882Svi117747 			mark = scan;
3662882Svi117747 			while (scan < uend && *scan != ';')
3672882Svi117747 				++scan;
3682882Svi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
3692882Svi117747 		}
3702882Svi117747 	} else {
3712882Svi117747 		ret = 1;
3722882Svi117747 	}
3732882Svi117747 
3742882Svi117747 	/*
3752882Svi117747 	 * parse area-specifier, service-provider, future-extension
3762882Svi117747 	 */
3772882Svi117747 	while (scan < uend && ret) {
3782882Svi117747 		if (uend - scan > 15 &&
3792882Svi117747 			!sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
3802882Svi117747 			scan += 15;
3812882Svi117747 			mark = scan;
3822882Svi117747 			while (scan < uend && *scan != ';')
3832882Svi117747 				++scan;
3842882Svi117747 			ret = sip_uri_parse_tel_areaspe(mark, scan);
3852882Svi117747 		} else if (uend - scan > 5 &&
3862882Svi117747 		    !sip_uri_url_casecmp(scan, ";tsp=", 5)) {
3872882Svi117747 			scan += 5;
3882882Svi117747 			mark = scan;
3892882Svi117747 			while (scan < uend && *scan != ';')
3902882Svi117747 				++scan;
3912882Svi117747 			ret = sip_uri_parse_tel_servicepro(mark, scan);
3922882Svi117747 		} else {
3932882Svi117747 			++scan;
3942882Svi117747 			mark = scan;
3952882Svi117747 			while (scan < uend && (*scan != ';' || quote)) {
3962882Svi117747 				if (sip_uri_hexVal(scan, uend) == 0x22) {
3972882Svi117747 					quote = !quote;
3982882Svi117747 					scan += 3;
3992882Svi117747 				} else {
4002882Svi117747 					++scan;
4012882Svi117747 				}
4022882Svi117747 			}
4032882Svi117747 			ret = sip_uri_parse_tel_futureext(mark, scan);
4042882Svi117747 		}
4052882Svi117747 	}
4062882Svi117747 	return (ret && scan == uend);
4072882Svi117747 }
4082882Svi117747 
4092882Svi117747 /*
4102882Svi117747  * area-specifier        = ";" phone-context-tag "=" phone-context-ident
4112882Svi117747  * phone-context-tag     = "phone-context"
4122882Svi117747  * phone-context-ident   = network-prefix / private-prefix
4132882Svi117747  * network-prefix        = global-network-prefix / local-network-prefix
4142882Svi117747  * global-network-prefix = "+" 1*phonedigit
4152882Svi117747  * local-network-prefix  = 1*(phonedigit / dtmf-digit / pause-character)
4162882Svi117747  * private-prefix        = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
4172882Svi117747  *                          %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
4182882Svi117747  *                          %x65-6F / %x71-76 / %x78-7E)
4192882Svi117747  *                          *(%x21-3A / %x3C-7E)
4202882Svi117747  * phonedigit            = DIGIT / visual-separator
4212882Svi117747  * visual-separator      = "-" / "." / "(" / ")"
4222882Svi117747  * pause-character       = one-second-pause / wait-for-dial-tone
4232882Svi117747  * one-second-pause      = "p"
4242882Svi117747  * wait-for-dial-tone    = "w"
4252882Svi117747  * dtmf-digit            = "*" / "#" / "A" / "B" / "C" / "D"
4262882Svi117747  */
4272882Svi117747 static int
sip_uri_parse_tel_areaspe(char * scan,char * uend)4282882Svi117747 sip_uri_parse_tel_areaspe(char *scan, char *uend)
4292882Svi117747 {
4302882Svi117747 	int	uri_hexValue;
4312882Svi117747 
4322882Svi117747 	if (scan == uend)
4332882Svi117747 		return (0);
4342882Svi117747 
4352882Svi117747 	/*
4362882Svi117747 	 * parse global-network-prefix
4372882Svi117747 	 */
4382882Svi117747 	if (*scan == '+') {
4392882Svi117747 		++scan;
4402882Svi117747 		if (scan == uend)
4412882Svi117747 			return (0);
4422882Svi117747 		while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
4432882Svi117747 			++scan;
4442882Svi117747 	/*
4452882Svi117747 	 * parse local-network-prefix
4462882Svi117747 	 */
4472882Svi117747 	} else if (SIP_URI_ISPHONEDIGIT(*scan) || SIP_URI_ISDTMFDIGIT(*scan) ||
4482882Svi117747 	    sip_uri_isEscapedPound(&scan, uend) ||
4492882Svi117747 	    *scan == 'p' || *scan == 'w') {
4502882Svi117747 		++scan;
4512882Svi117747 		while (scan < uend &&
4522882Svi117747 		    (SIP_URI_ISPHONEDIGIT(*scan) ||
4532882Svi117747 		    SIP_URI_ISDTMFDIGIT(*scan) ||
4542882Svi117747 		    sip_uri_isEscapedPound(&scan, uend) ||
4552882Svi117747 		    *scan == 'p' || *scan == 'w')) {
4562882Svi117747 			++scan;
4572882Svi117747 		}
4582882Svi117747 	} else {
4592882Svi117747 	/*
4602882Svi117747 	 * parse private-prefix
4612882Svi117747 	 *
4622882Svi117747 	 * any characters allowed in RFC 2806 that are not allowed in
4632882Svi117747 	 * the user part of the SIP URI MUST be escaped
4642882Svi117747 	 *
4652882Svi117747 	 * private-prefix	= (! $ & ', / = ? _
4662882Svi117747 	 *			EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
4672882Svi117747 	 *			{ } | ~ [ ] \ ^  ` " % : < > @)
4682882Svi117747 	 *			*(%x21-3A / %x3C-7E)
4692882Svi117747 	 *
4702882Svi117747 	 * following characters are allowed in RFC 2806 and
4712882Svi117747 	 * the user part of SIP URI
4722882Svi117747 	 *  ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
4732882Svi117747 	 */
4742882Svi117747 		if (*scan == '!' || *scan == '$' || *scan == '&' ||
4752882Svi117747 		    *scan == '\'' || *scan == ',' || *scan == '/' ||
4762882Svi117747 		    *scan == '=' || *scan == '?' || *scan == '_' ||
4772882Svi117747 		    (*scan >= 'E' && *scan <= 'Z' &&
4782882Svi117747 		    *scan != 'P' && *scan != 'W') ||
4792882Svi117747 		    (*scan >= 'e' && *scan <= 'z' &&
4802882Svi117747 		    *scan != 'p' && *scan != 'w')) {
4812882Svi117747 			++scan;
4822882Svi117747 		} else {
4832882Svi117747 			uri_hexValue = sip_uri_hexVal(scan, uend);
4842882Svi117747 			if (uri_hexValue == 0x21 || uri_hexValue == 0x22 ||
4852882Svi117747 			    (uri_hexValue >= 0x24 && uri_hexValue <= 0x27) ||
4862882Svi117747 			    uri_hexValue == 0x2c || uri_hexValue == 0x2f ||
4872882Svi117747 			    uri_hexValue == 0x3a ||
4882882Svi117747 			    (uri_hexValue >= 0x3c && uri_hexValue <= 0x40) ||
4892882Svi117747 			    (uri_hexValue >= 0x45 && uri_hexValue <= 0x4f) ||
4902882Svi117747 			    (uri_hexValue >= 0x51 && uri_hexValue <= 0x56) ||
4912882Svi117747 			    (uri_hexValue >= 0x58 && uri_hexValue <= 0x60) ||
4922882Svi117747 			    (uri_hexValue >= 0x65 && uri_hexValue <= 0x6f) ||
4932882Svi117747 			    (uri_hexValue >= 0x71 && uri_hexValue <= 0x76) ||
4942882Svi117747 			    (uri_hexValue >= 0x78 && uri_hexValue <= 0x7e)) {
4952882Svi117747 				scan += 3;
4962882Svi117747 			} else {
4972882Svi117747 				return (0);
4982882Svi117747 			}
4992882Svi117747 		}
5002882Svi117747 		/*
5012882Svi117747 		 * parse *(%x21-3A / %x3C-7E)
5022882Svi117747 		 */
5032882Svi117747 		while (scan < uend) {
5042882Svi117747 			if (SIP_URI_ISUNRESERVED(*scan) ||
5052882Svi117747 			    (SIP_URI_ISUSER(*scan) && *scan != ';')) {
5062882Svi117747 				++scan;
5072882Svi117747 			} else {
5082882Svi117747 				uri_hexValue = sip_uri_hexVal(scan, uend);
5092882Svi117747 				if (uri_hexValue >= 0x21 &&
5102882Svi117747 				    uri_hexValue <= 0x7e &&
5112882Svi117747 				    uri_hexValue != 0x3b) {
5122882Svi117747 					scan += 3;
5132882Svi117747 				} else {
5142882Svi117747 					return (0);
5152882Svi117747 				}
5162882Svi117747 			}
5172882Svi117747 		}
5182882Svi117747 	}
5192882Svi117747 	if (scan < uend)
5202882Svi117747 		return (0);
5212882Svi117747 	return (1);
5222882Svi117747 }
5232882Svi117747 
5242882Svi117747 static int
sip_uri_hexVal(char * scan,char * uend)5252882Svi117747 sip_uri_hexVal(char *scan, char *uend)
5262882Svi117747 {
5272882Svi117747 	int	ret = -1;
5282882Svi117747 
5292882Svi117747 	if (SIP_URI_ISURLESCAPE(scan, uend)) {
5302882Svi117747 		ret = (SIP_URI_ISDIGIT(scan[1]) ? (scan[1] - '0') :
5312882Svi117747 		    (tolower(scan[1]) - 'a' + 10)) * 16 +
5322882Svi117747 		    (SIP_URI_ISDIGIT(scan[2]) ? (scan[2] - '0') :
5332882Svi117747 		    (tolower(scan[2]) - 'a' + 10));
5342882Svi117747 	}
5352882Svi117747 	return (ret);
5362882Svi117747 }
5372882Svi117747 
5382882Svi117747 /*
5392882Svi117747  * service-provider  = ";" provider-tag "=" provider-hostname
5402882Svi117747  * provider-tag      = "tsp"
5412882Svi117747  * provider-hostname = domain
5422882Svi117747  */
5432882Svi117747 static int
sip_uri_parse_tel_servicepro(char * scan,char * uend)5442882Svi117747 sip_uri_parse_tel_servicepro(char *scan, char *uend)
5452882Svi117747 {
5462882Svi117747 	char	*mark = (char *)0;
5472882Svi117747 
5482882Svi117747 	if (scan == uend)
5492882Svi117747 		return (0);
5502882Svi117747 
5512882Svi117747 	/*
5522882Svi117747 	 * parse domain=" "
5532882Svi117747 	 */
5542882Svi117747 	if (sip_uri_hexVal(scan, uend) == 0x20 && scan + 3 == uend)
5552882Svi117747 		return (1);
5562882Svi117747 	while (scan < uend) {
5572882Svi117747 		mark = scan;
5582882Svi117747 		while (scan < uend && (*scan == '-'|| SIP_URI_ISALNUM(*scan)))
5592882Svi117747 			++scan;
5602882Svi117747 		if ((scan < uend && *scan != '.') ||
5612882Svi117747 		    !SIP_URI_ISALPHA(*mark) || !SIP_URI_ISALNUM(*(scan - 1))) {
5622882Svi117747 			return (0);
5632882Svi117747 		}
5642882Svi117747 		if (scan < uend)
5652882Svi117747 			++scan;
5662882Svi117747 	}
5672882Svi117747 
5682882Svi117747 	if (scan < uend)
5692882Svi117747 		return (0);
5702882Svi117747 	return (1);
5712882Svi117747 }
5722882Svi117747 
5732882Svi117747 /*
5742882Svi117747  * future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
5752882Svi117747  *                    ["?" 1*(token-char)]) / quoted-string )]
5762882Svi117747  * token-char       = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
5772882Svi117747  *                     / %x41-5A / %x5E-7A / %x7C / %x7E)
5782882Svi117747  */
5792882Svi117747 static int
sip_uri_parse_tel_futureext(char * scan,char * uend)5802882Svi117747 sip_uri_parse_tel_futureext(char *scan, char *uend)
5812882Svi117747 {
5822882Svi117747 	char	*mark;
5832882Svi117747 	int	uri_hexValue = 0;
5842882Svi117747 
5852882Svi117747 	if (scan == uend)
5862882Svi117747 		return (0);
5872882Svi117747 
5882882Svi117747 	/*
5892882Svi117747 	 * parse 1*(token-char)
5902882Svi117747 	 */
5912882Svi117747 	mark = scan;
5922882Svi117747 	while (scan < uend && sip_uri_isTokenchar(&scan, uend))
5932882Svi117747 		;
5942882Svi117747 	if (mark == scan ||
5952882Svi117747 	    (scan < uend && (*scan != '=' || scan + 1 == uend))) {
5962882Svi117747 		return (0);
5972882Svi117747 	}
5982882Svi117747 	if (scan == uend)
5992882Svi117747 		return (1);
6002882Svi117747 	++scan;
6012882Svi117747 
6022882Svi117747 	/*
6032882Svi117747 	 * parse 1*token-char ["?" 1*token-char]
6042882Svi117747 	 */
6052882Svi117747 	if (sip_uri_isTokenchar(&scan, uend)) {
6062882Svi117747 		while (sip_uri_isTokenchar(&scan, uend))
6072882Svi117747 			;
6082882Svi117747 		if (scan < uend) {
6092882Svi117747 			if (*scan != '?')
6102882Svi117747 				return (0);
6112882Svi117747 			++scan;
6122882Svi117747 			mark = scan;
6132882Svi117747 			while (sip_uri_isTokenchar(&scan, uend))
6142882Svi117747 				;
6152882Svi117747 			if (mark == scan)
6162882Svi117747 				return (0);
6172882Svi117747 		}
6182882Svi117747 	} else { /* parse quoted-string */
6192882Svi117747 		uri_hexValue = sip_uri_hexVal(scan, uend);
6202882Svi117747 		if (uri_hexValue != 0x22)
6212882Svi117747 			return (0);
6222882Svi117747 		scan += 3;
6232882Svi117747 		while (scan < uend && sip_uri_hexVal(scan, uend) != 0x22) {
6242882Svi117747 			/*
6252882Svi117747 			 * parse "\" CHAR
6262882Svi117747 			 */
6272882Svi117747 			if (sip_uri_hexVal(scan, uend) == 0x5c) {
6282882Svi117747 				scan += 3;
6292882Svi117747 				if (scan < uend) {
6302882Svi117747 					if (SIP_URI_ISUNRESERVED(*scan) ||
6312882Svi117747 					    SIP_URI_ISUSER(*scan)) {
6322882Svi117747 						++scan;
6332882Svi117747 					} else if (sip_uri_hexVal(scan, uend) >=
6342882Svi117747 					    0x00 &&
6352882Svi117747 					    sip_uri_hexVal(scan, uend) <=
6362882Svi117747 					    0x7f) {
6372882Svi117747 						scan += 3;
6382882Svi117747 					} else {
6392882Svi117747 						return (0);
6402882Svi117747 					}
6412882Svi117747 				} else {
6422882Svi117747 					return (0);
6432882Svi117747 				}
6442882Svi117747 			} else {
6452882Svi117747 				if (SIP_URI_ISUNRESERVED(*scan) ||
6462882Svi117747 				    SIP_URI_ISUSER(*scan)) {
6472882Svi117747 					++scan;
6482882Svi117747 				} else {
6492882Svi117747 					uri_hexValue =
6502882Svi117747 					    sip_uri_hexVal(scan, uend);
6512882Svi117747 					if ((uri_hexValue >= 0x20 &&
6522882Svi117747 						uri_hexValue <= 0x21) ||
6532882Svi117747 						(uri_hexValue >= 0x23 &&
6542882Svi117747 						uri_hexValue <= 0x7e) ||
6552882Svi117747 						(uri_hexValue >= 0x80 &&
6562882Svi117747 						uri_hexValue <= 0xff)) {
6572882Svi117747 						scan += 3;
6582882Svi117747 					} else {
6592882Svi117747 						return (0);
6602882Svi117747 					}
6612882Svi117747 				}
6622882Svi117747 			}
6632882Svi117747 		}
6642882Svi117747 		if (scan == uend ||
6652882Svi117747 		    (scan < uend && sip_uri_hexVal(scan, uend) != 0x22)) {
6662882Svi117747 			return (0);
6672882Svi117747 		}
6682882Svi117747 		scan += 3;
6692882Svi117747 	}
6702882Svi117747 
6712882Svi117747 	if (scan < uend)
6722882Svi117747 		return (0);
6732882Svi117747 	return (1);
6742882Svi117747 }
6752882Svi117747 
6762882Svi117747 /*
6772882Svi117747  * Any characters allowed in RFC2806 tel URL that are not allowed in
6782882Svi117747  * the user part of the SIP URI MUST be escaped.
6792882Svi117747  * token-char = - _ . ! ~ * ' $ &  + DIGIT ALPHA #  % ^ ` |
6802882Svi117747  */
6812882Svi117747 static int
sip_uri_isTokenchar(char ** pscan,char * uend)6822882Svi117747 sip_uri_isTokenchar(char **pscan, char *uend)
6832882Svi117747 {
6842882Svi117747 	char	*scan = *pscan;
6852882Svi117747 	int	uri_hexValue = 0;
6862882Svi117747 
6872882Svi117747 	if (scan == uend)
6882882Svi117747 		return (0);
6892882Svi117747 
6902882Svi117747 	/*
6912882Svi117747 	 * for ALPAH DIGIT - _ . ! ~ * ' $ & +
6922882Svi117747 	 */
6932882Svi117747 	if ((SIP_URI_ISUNRESERVED(*scan) && *scan != '(' && *scan != ')') ||
6942882Svi117747 	    *scan == '$' || *scan == '&' || *scan == '+') {
6952882Svi117747 		++scan;
6962882Svi117747 		*pscan = scan;
6972882Svi117747 		return (1);
6982882Svi117747 	}
6992882Svi117747 
7002882Svi117747 	uri_hexValue = sip_uri_hexVal(scan, uend);
7012882Svi117747 	if (uri_hexValue == 0x21 || uri_hexValue == 0x7c ||
7022882Svi117747 	    uri_hexValue == 0x7e ||
7032882Svi117747 	    (uri_hexValue >= 0x23 && uri_hexValue <= 0x27) ||
7042882Svi117747 	    (uri_hexValue >= 0x2a && uri_hexValue <= 0x2b) ||
7052882Svi117747 	    (uri_hexValue >= 0x2d && uri_hexValue <= 0x2e) ||
7062882Svi117747 	    (uri_hexValue >= 0x30 && uri_hexValue <= 0x39) ||
7072882Svi117747 	    (uri_hexValue >= 0x41 && uri_hexValue <= 0x5a) ||
7082882Svi117747 	    (uri_hexValue >= 0x5e && uri_hexValue <= 0x7a)) {
7092882Svi117747 		scan += 3;
7102882Svi117747 		*pscan = scan;
7112882Svi117747 		return (1);
7122882Svi117747 	}
7132882Svi117747 	return (0);
7142882Svi117747 }
7152882Svi117747 
7162882Svi117747 /*
7172882Svi117747  * '#' is not allowed in the telephone-subscriber part of SIP URI
7182882Svi117747  * it must be escaped
7192882Svi117747  */
7202882Svi117747 static int
sip_uri_isEscapedPound(char ** pscan,char * uend)7212882Svi117747 sip_uri_isEscapedPound(char **pscan, char *uend)
7222882Svi117747 {
7232882Svi117747 	char	*scan = *pscan;
7242882Svi117747 
7252882Svi117747 	if (scan == uend)
7262882Svi117747 		return (0);
7272882Svi117747 	if (*scan == '%' && scan + 2 < uend && scan[1] == '2' &&
7282882Svi117747 	    scan[2] == '3') {
7292882Svi117747 		scan += 2;
7302882Svi117747 		*pscan = scan;
7312882Svi117747 		return (1);
7322882Svi117747 	}
7332882Svi117747 	return (0);
7342882Svi117747 }
7352882Svi117747 
7362882Svi117747 /*
7372882Svi117747  * scheme =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
7382882Svi117747  */
7392882Svi117747 static int
sip_uri_parse_scheme(_sip_uri_t * outurl,char * scan,char * uend)7402882Svi117747 sip_uri_parse_scheme(_sip_uri_t *outurl, char *scan, char *uend)
7412882Svi117747 {
7422882Svi117747 	if (scan == uend) {
7432882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
7442882Svi117747 		return (0);
7452882Svi117747 	}
7462882Svi117747 	outurl->sip_uri_scheme.sip_str_ptr = scan;
7472882Svi117747 	outurl->sip_uri_scheme.sip_str_len = uend - scan;
7482882Svi117747 
7492882Svi117747 	if (scan < uend && SIP_URI_ISALPHA(*scan)) {
7502882Svi117747 		++scan;
7512882Svi117747 		while (scan < uend && SIP_URI_ISSCHEME(*scan))
7522882Svi117747 			++scan;
7532882Svi117747 	}
7542882Svi117747 	if (scan < uend)
7552882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
7562882Svi117747 	return (1);
7572882Svi117747 }
7582882Svi117747 
7592882Svi117747 /*
7602882Svi117747  * The format of params is supposed to be;XXX;XXX;XXX
7612882Svi117747  * uri-parameters	= *(";" uri-parameter)
7622882Svi117747  * uri-parameter	= transport-param / user-param / method-param
7632882Svi117747  * 			/ ttl-param / maddr-param / lr-param / other-param
7642882Svi117747  * transport-param	=  "transport="
7652882Svi117747  *			("udp" / "tcp" / "sctp" / "tls" / other-transport)
7662882Svi117747  * other-transport		=  token
7672882Svi117747  * user-param		=  "user=" ("phone" / "ip" / other-user)
7682882Svi117747  * other-user		=  token
7692882Svi117747  * method-param		=  "method=" Method
7702882Svi117747  * ttl-param		=  "ttl=" ttl
7712882Svi117747  * maddr-param		=  "maddr=" host
7722882Svi117747  * lr-param		=  "lr"
7732882Svi117747  * other-param		=  pname [ "=" pvalue ]
7742882Svi117747  * pname		=  1*paramchar
7752882Svi117747  * pvalue		=  1*paramchar
7762882Svi117747  * paramchar		=  param-unreserved / unreserved / escaped
7772882Svi117747  * param-unreserved	=  "[" / "]" / "/" / ":" / "&" / "+" / "$"
7782882Svi117747  */
7792882Svi117747 static void
sip_uri_parse_params(_sip_uri_t * outurl,char * scan,char * uend)7802882Svi117747 sip_uri_parse_params(_sip_uri_t *outurl, char *scan, char *uend)
7812882Svi117747 {
7822882Svi117747 	char		*mark = (char *)0;
7832882Svi117747 	char		*equal = (char *)0;
7842882Svi117747 	int		i = 0;
7852882Svi117747 	int		ttl = 0;
7862882Svi117747 	int		paramleftlen = 0;
7872882Svi117747 	int		gothost = 0;
7882882Svi117747 	sip_param_t	*param = NULL;
7892882Svi117747 	sip_param_t	*new_param = NULL;
7902882Svi117747 
7912882Svi117747 	if (scan == uend || *scan != ';' || scan + 1 == uend) {
7922882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
7932882Svi117747 		return;
7942882Svi117747 	}
7952882Svi117747 
7962882Svi117747 	while (scan < uend) {
7972882Svi117747 		mark = ++scan;
7982882Svi117747 		while (scan < uend && *scan != ';')
7992882Svi117747 			++scan;
8002882Svi117747 		if (scan == mark) {
8012882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
8022882Svi117747 			return;
8032882Svi117747 		}
8042882Svi117747 
8052882Svi117747 		new_param = calloc(1, sizeof (sip_param_t));
8062882Svi117747 		if (new_param == NULL) {
8072882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_MEMORY;
8082882Svi117747 			return;
8092882Svi117747 		}
8102882Svi117747 
8112882Svi117747 		if (param == NULL)
8122882Svi117747 			outurl->sip_uri_params = new_param;
8132882Svi117747 		else
8142882Svi117747 			param->param_next = new_param;
8152882Svi117747 
8162882Svi117747 		param = new_param;
8172882Svi117747 
8182882Svi117747 		param->param_name.sip_str_ptr = mark;
8192882Svi117747 		equal = memchr(mark, '=', scan - mark);
8202882Svi117747 		if (equal == (char *)0) {
8212882Svi117747 			param->param_name.sip_str_len = scan - mark;
8222882Svi117747 			param->param_value.sip_str_ptr = NULL;
8232882Svi117747 			param->param_value.sip_str_len = 0;
8242882Svi117747 			while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
8252882Svi117747 			    SIP_URI_ISURLESCAPE(mark, scan))) {
8262882Svi117747 				++mark;
8272882Svi117747 			}
8282882Svi117747 		} else {
8292882Svi117747 			param->param_name.sip_str_len = equal - mark;
8302882Svi117747 			param->param_value.sip_str_ptr = equal + 1;
8312882Svi117747 			param->param_value.sip_str_len = scan - equal - 1;
8322882Svi117747 
8332882Svi117747 			if (mark == equal || equal + 1 == scan) {
8342882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
8352882Svi117747 				return;
8362882Svi117747 			}
8372882Svi117747 			paramleftlen = equal - mark + 1;
8382882Svi117747 			if ((paramleftlen == 10 &&
8392882Svi117747 			    !sip_uri_url_casecmp(mark, "transport=", 10)) ||
8402882Svi117747 			    (paramleftlen == 5 &&
8412882Svi117747 			    !sip_uri_url_casecmp(mark, "user=", 5)) ||
8422882Svi117747 			    (paramleftlen == 7 &&
8432882Svi117747 			    !sip_uri_url_casecmp(mark, "method=", 7))) {
8442882Svi117747 				if (scan - equal == 1) {
8452882Svi117747 					outurl->sip_uri_errflags |=
8462882Svi117747 					    SIP_URIERR_PARAM;
8472882Svi117747 					return;
8482882Svi117747 				}
8492882Svi117747 				mark = equal + 1;
8502882Svi117747 				while (mark < scan && SIP_URI_ISTOKEN(*mark))
8512882Svi117747 					++mark;
8522882Svi117747 			} else if (paramleftlen == 4 &&
8532882Svi117747 			    !sip_uri_url_casecmp(mark, "ttl=", 4)) {
8542882Svi117747 				if (scan - equal == 1) {
8552882Svi117747 					outurl->sip_uri_errflags |=
8562882Svi117747 					    SIP_URIERR_PARAM;
8572882Svi117747 					return;
8582882Svi117747 				}
8592882Svi117747 				mark = equal;
8602882Svi117747 				for (i = 0; i < 3; ++i) {
8612882Svi117747 					++mark;
8622882Svi117747 					if (mark < scan &&
8632882Svi117747 					    SIP_URI_ISDIGIT(*mark)) {
8642882Svi117747 						ttl = ttl * 10 + (*mark - '0');
8652882Svi117747 					}
8662882Svi117747 					if (ttl > 255) {
8672882Svi117747 						outurl->sip_uri_errflags |=
8682882Svi117747 							SIP_URIERR_PARAM;
8692882Svi117747 						return;
8702882Svi117747 					}
8712882Svi117747 				}
8722882Svi117747 			} else if (paramleftlen == 6 &&
8732882Svi117747 			    !sip_uri_url_casecmp(mark, "maddr=", 6)) {
8742882Svi117747 				gothost = 0;
8752882Svi117747 				mark = equal + 1;
8762882Svi117747 				if (mark < scan && SIP_URI_ISDIGIT(*mark)) {
8772882Svi117747 					gothost = sip_uri_parse_ipv4(mark,
8782882Svi117747 					    scan);
8792882Svi117747 				}
8802882Svi117747 				/*
8812882Svi117747 				 * not valid syntax for a host or user name,
8822882Svi117747 				 * try IPv6 literal
8832882Svi117747 				 */
8842882Svi117747 				if (!gothost && mark < scan && *mark == '[') {
8852882Svi117747 					gothost = sip_uri_parse_ipv6(mark,
8862882Svi117747 					    scan);
8872882Svi117747 				}
8882882Svi117747 				/*
8892882Svi117747 				 * look for a valid host name:
8902882Svi117747 				 * *(domainlabel ".") toplabel ["."]
8912882Svi117747 				 */
8922882Svi117747 				if (!gothost && mark < scan) {
8932882Svi117747 					if (!(gothost =
8942882Svi117747 					    sip_uri_parse_hostname(mark,
8952882Svi117747 					    scan))) {
8962882Svi117747 						outurl->sip_uri_errflags |=
8972882Svi117747 							SIP_URIERR_PARAM;
8982882Svi117747 					}
8992882Svi117747 				}
9002882Svi117747 				if (gothost)
9012882Svi117747 					mark = scan;
9022882Svi117747 			} else if (paramleftlen == 3 &&
9032882Svi117747 			    !sip_uri_url_casecmp(mark, "lr=", 3)) {
9042882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
9052882Svi117747 				return;
9062882Svi117747 			} else {
9072882Svi117747 				while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
9082882Svi117747 				    SIP_URI_ISURLESCAPE(mark, scan) ||
9092882Svi117747 				    mark == equal)) {
9102882Svi117747 					++mark;
9112882Svi117747 				}
9122882Svi117747 			}
9132882Svi117747 		}
9142882Svi117747 		if (mark < scan) {
9152882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
9162882Svi117747 			return;
9172882Svi117747 		}
9182882Svi117747 	}
9192882Svi117747 }
9202882Svi117747 
9212882Svi117747 /*
9222882Svi117747  * The format of headers is supposed to be ?XXX&XXX&XXX
9232882Svi117747  * headers         =  "?" header *("&" header
9242882Svi117747  * header          =  hname "=" hvalue
9252882Svi117747  * hname           =  1*(hnv-unreserved / unreserved / escaped
9262882Svi117747  * hvalue          =  *(hnv-unreserved / unreserved / escaped
9272882Svi117747  * hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
9282882Svi117747  */
9292882Svi117747 static void
sip_uri_parse_headers(_sip_uri_t * outurl,char * scan,char * uend)9302882Svi117747 sip_uri_parse_headers(_sip_uri_t *outurl, char *scan, char *uend)
9312882Svi117747 {
9322882Svi117747 	char	*mark = NULL;
9332882Svi117747 	char	*equal = NULL;
9342882Svi117747 
9352882Svi117747 	if (scan == uend || *scan != '?' || scan + 1 == uend) {
9362882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
9372882Svi117747 		return;
9382882Svi117747 	}
9392882Svi117747 	outurl->sip_uri_headers.sip_str_ptr = scan + 1;
9402882Svi117747 	outurl->sip_uri_headers.sip_str_len = uend - (scan + 1);
9412882Svi117747 
9422882Svi117747 	while (scan < uend) {
9432882Svi117747 		mark = ++scan;
9442882Svi117747 		while (scan < uend && *scan != '&')
9452882Svi117747 			++scan;
9462882Svi117747 		if (scan == mark) {
9472882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
9482882Svi117747 			return;
9492882Svi117747 		}
9502882Svi117747 		equal = memchr(mark, '=', scan - mark);
9512882Svi117747 		if (equal == mark || equal == (char *)0) {
9522882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
9532882Svi117747 			return;
9542882Svi117747 		}
9552882Svi117747 		while (mark < scan &&
9562882Svi117747 		    (SIP_URI_ISHEADER(*mark) ||
9572882Svi117747 		    SIP_URI_ISURLESCAPE(mark, scan) || mark == equal)) {
9582882Svi117747 			++mark;
9592882Svi117747 		}
9602882Svi117747 		if (mark < scan) {
9612882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
9622882Svi117747 			return;
9632882Svi117747 		}
9642882Svi117747 	}
9652882Svi117747 }
9662882Svi117747 
9672882Svi117747 /*
9682882Svi117747  * opaque-part   =  uric-no-slash *uric
9692882Svi117747  * uric          =  reserved / unreserved / escaped
9702882Svi117747  * uric-no-slash =  unreserved / escaped / ";" / "?" / ":" / "@"
9712882Svi117747  *                  / "&" / "=" / "+" / "$" / ","
9722882Svi117747  */
9732882Svi117747 static void
sip_uri_parse_abs_opaque(_sip_uri_t * outurl,char * scan,char * uend)9742882Svi117747 sip_uri_parse_abs_opaque(_sip_uri_t *outurl, char *scan, char *uend)
9752882Svi117747 {
9762882Svi117747 	if (scan == uend) {
9772882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
9782882Svi117747 		return;
9792882Svi117747 	}
9802882Svi117747 	outurl->sip_uri_opaque.sip_str_ptr = scan;
9812882Svi117747 	outurl->sip_uri_opaque.sip_str_len = uend - scan;
9822882Svi117747 
9832882Svi117747 	if (SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
9842882Svi117747 	    SIP_URI_ISOTHER(*scan) || *scan == ';' || *scan == '?' ||
9852882Svi117747 	    *scan == ':' || *scan == '@' || *scan == '&') {
9862882Svi117747 		++scan;
9872882Svi117747 	} else {
9882882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
9892882Svi117747 		return;
9902882Svi117747 	}
9912882Svi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
9922882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
9932882Svi117747 		++scan;
9942882Svi117747 	}
9952882Svi117747 	if (scan < uend)
9962882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
9972882Svi117747 }
9982882Svi117747 
9992882Svi117747 /*
10002882Svi117747  * format of query is supposed to be ?XXX
10012882Svi117747  * query =  *uric
10022882Svi117747  * uric  =  reserved / unreserved / escaped
10032882Svi117747  */
10042882Svi117747 static void
sip_uri_parse_abs_query(_sip_uri_t * outurl,char * scan,char * uend)10052882Svi117747 sip_uri_parse_abs_query(_sip_uri_t *outurl, char *scan, char *uend)
10062882Svi117747 {
10072882Svi117747 	if (uend == scan || *scan != '?' || scan + 1 == uend)
10082882Svi117747 		return;
10092882Svi117747 	++scan;
10102882Svi117747 	outurl->sip_uri_query.sip_str_ptr = scan;
10112882Svi117747 	outurl->sip_uri_query.sip_str_len = uend - scan;
10122882Svi117747 
10132882Svi117747 	while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
10142882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
10152882Svi117747 		++scan;
10162882Svi117747 	}
10172882Svi117747 	if (scan < uend)
10182882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_QUERY;
10192882Svi117747 }
10202882Svi117747 
10212882Svi117747 /*
10222882Svi117747  * the format of path is supposed to be /XXX;XXX/XXX;
10232882Svi117747  * abs-path       =  "/" path-segments
10242882Svi117747  * path-segments  =  segment *( "/" segment )
10252882Svi117747  * segment        =  *pchar *( ";" param )
10262882Svi117747  * param          =  *pchar
10272882Svi117747  * pchar          =  unreserved / escaped /
10282882Svi117747  *                   ":" / "@" / "&" / "=" / "+" / "$" / ","
10292882Svi117747  */
10302882Svi117747 static void
sip_uri_parse_abs_path(_sip_uri_t * outurl,char * scan,char * uend)10312882Svi117747 sip_uri_parse_abs_path(_sip_uri_t *outurl, char *scan, char *uend)
10322882Svi117747 {
10332882Svi117747 	if (scan == uend || *scan != '/')
10342882Svi117747 		return;
10352882Svi117747 	outurl->sip_uri_path.sip_str_ptr = scan;
10362882Svi117747 	outurl->sip_uri_path.sip_str_len = uend - scan;
10372882Svi117747 
10382882Svi117747 	++scan;
10392882Svi117747 	while (scan < uend && (SIP_URI_ISPCHAR(*scan) ||
10402882Svi117747 	    SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
10412882Svi117747 	    *scan == '/' || *scan == ';')) {
10422882Svi117747 		++scan;
10432882Svi117747 	}
10442882Svi117747 	if (scan < uend)
10452882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PATH;
10462882Svi117747 }
10472882Svi117747 /*
10482882Svi117747  * reg-name =  1*( unreserved / escaped / "$" / "," / ";"
10492882Svi117747  *             / ":" / "@" / "&" / "=" / "+" )
10502882Svi117747  */
10512882Svi117747 static void
sip_uri_parse_abs_regname(_sip_uri_t * outurl,char * scan,char * uend)10522882Svi117747 sip_uri_parse_abs_regname(_sip_uri_t *outurl, char *scan, char *uend)
10532882Svi117747 {
10542882Svi117747 	if (scan == uend)
10552882Svi117747 		return;
10562882Svi117747 	outurl->sip_uri_regname.sip_str_ptr = scan;
10572882Svi117747 	outurl->sip_uri_regname.sip_str_len = uend - scan;
10582882Svi117747 
10592882Svi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
10602882Svi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISREGNAME(*scan))) {
10612882Svi117747 		++scan;
10622882Svi117747 	}
10632882Svi117747 	if (scan < uend)
10642882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_REGNAME;
10652882Svi117747 }
10662882Svi117747 
10672882Svi117747 /*
10682882Svi117747  * The format of the password is supposed to be :XXX
10692882Svi117747  * password =  *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
10702882Svi117747  */
10712882Svi117747 static void
sip_uri_parse_password(_sip_uri_t * outurl,char * scan,char * uend)10722882Svi117747 sip_uri_parse_password(_sip_uri_t *outurl, char *scan, char *uend)
10732882Svi117747 {
10742882Svi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend)
10752882Svi117747 		return;
10762882Svi117747 	++scan;
10772882Svi117747 	outurl->sip_uri_password.sip_str_ptr = scan;
10782882Svi117747 	outurl->sip_uri_password.sip_str_len = uend - scan;
10792882Svi117747 
10802882Svi117747 	while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
10812882Svi117747 	    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISOTHER(*scan) ||
10822882Svi117747 	    *scan == '&')) {
10832882Svi117747 		++scan;
10842882Svi117747 	}
10852882Svi117747 	if (scan < uend)
10862882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PASS;
10872882Svi117747 }
10882882Svi117747 
10892882Svi117747 /*
10902882Svi117747  * user =  1*( unreserved / escaped / user-unreserved )
10912882Svi117747  * user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
10922882Svi117747  */
10932882Svi117747 static void
sip_uri_parse_user(_sip_uri_t * outurl,char * scan,char * uend)10942882Svi117747 sip_uri_parse_user(_sip_uri_t *outurl, char *scan, char *uend)
10952882Svi117747 {
10962882Svi117747 	if (scan == uend) {
10972882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_USER;
10982882Svi117747 		return;
10992882Svi117747 	}
11002882Svi117747 	outurl->sip_uri_user.sip_str_ptr = scan;
11012882Svi117747 	outurl->sip_uri_user.sip_str_len = uend - scan;
11022882Svi117747 
11032882Svi117747 	if (sip_uri_parse_tel(scan, uend)) {
11042882Svi117747 		outurl->sip_uri_isteluser = B_TRUE;
11052882Svi117747 	} else {
11062882Svi117747 		while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
11072882Svi117747 		    SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISUSER(*scan))) {
11082882Svi117747 			++scan;
11092882Svi117747 		}
11102882Svi117747 		if (scan < uend)
11112882Svi117747 			outurl->sip_uri_errflags |= SIP_URIERR_USER;
11122882Svi117747 	}
11132882Svi117747 }
11142882Svi117747 
11152882Svi117747 /*
11162882Svi117747  * the format of port is supposed to be :XXX
11172882Svi117747  * port =  1*DIGIT
11182882Svi117747  */
11192882Svi117747 static void
sip_uri_parse_port(_sip_uri_t * outurl,char * scan,char * uend)11202882Svi117747 sip_uri_parse_port(_sip_uri_t *outurl, char *scan, char *uend)
11212882Svi117747 {
11222882Svi117747 	if (scan == uend || *scan != ':' || scan + 1 == uend) {
11232882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
11242882Svi117747 		return;
11252882Svi117747 	}
11262882Svi117747 	++scan;
11272882Svi117747 	/*
11282882Svi117747 	 * parse numeric port number
11292882Svi117747 	 */
11302882Svi117747 	if (SIP_URI_ISDIGIT(*scan)) {
11312882Svi117747 		outurl->sip_uri_port = *scan - '0';
11322882Svi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
11332882Svi117747 		    outurl->sip_uri_port =
11342882Svi117747 			outurl->sip_uri_port * 10 + (*scan - '0');
11352882Svi117747 			if (outurl->sip_uri_port > 0xffff) {
11362882Svi117747 				outurl->sip_uri_errflags |= SIP_URIERR_PORT;
11372882Svi117747 				outurl->sip_uri_port = 0;
11382882Svi117747 				break;
11392882Svi117747 			}
11402882Svi117747 		}
11412882Svi117747 	}
11422882Svi117747 	if (scan < uend) {
11432882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_PORT;
11442882Svi117747 		outurl->sip_uri_port = 0;
11452882Svi117747 	}
11462882Svi117747 }
11472882Svi117747 
11482882Svi117747 /*
11492882Svi117747  * parse an IPv4 address
11502882Svi117747  *    1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
11512882Svi117747  *  advances pscan to end of IPv4 address, or after last "." that was
11522882Svi117747  *  a valid IPv4 or domain name.
11532882Svi117747  * returns 1 if ipv4 found, 0 otherwise
11542882Svi117747  */
11552882Svi117747 static int
sip_uri_parse_ipv4(char * scan,char * uend)11562882Svi117747 sip_uri_parse_ipv4(char *scan, char *uend)
11572882Svi117747 {
11582882Svi117747 	int	j = 0;
11592882Svi117747 	int	val = 0;
11602882Svi117747 
11612882Svi117747 	for (j = 0; j < 4; ++j) {
11622882Svi117747 		if (!SIP_URI_ISDIGIT(*scan))
11632882Svi117747 			break;
11642882Svi117747 		val = *scan - '0';
11652882Svi117747 		while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
11662882Svi117747 			val = val * 10 + (*scan - '0');
11672882Svi117747 			if (val > 255)
11682882Svi117747 				return (0);
11692882Svi117747 		}
11702882Svi117747 		if (j < 3) {
11712882Svi117747 			if (*scan != '.')
11722882Svi117747 				break;
11732882Svi117747 			++scan;
11742882Svi117747 		}
11752882Svi117747 	}
11762882Svi117747 
11772882Svi117747 	if (j == 4 && scan == uend)
11782882Svi117747 		return (1);
11792882Svi117747 
11802882Svi117747 	return (0);
11812882Svi117747 }
11822882Svi117747 
11832882Svi117747 /*
11842882Svi117747  * parse an IPv6 address
11852882Svi117747  *  IPv6address = hexpart [ ":" IPv4address ]
11862882Svi117747  *  IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
11872882Svi117747  *  hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
11882882Svi117747  *  hexseq  = hex4 *( ":" hex4)
11892882Svi117747  *  hex4    = 1*4HEXDIG
11902882Svi117747  *  if not found, leaves pscan unchanged, otherwise advances to end
11912882Svi117747  *  returns 1 if valid,
11922882Svi117747  *  0 if invalid
11932882Svi117747  */
11942882Svi117747 static int
sip_uri_parse_ipv6(char * scan,char * uend)11952882Svi117747 sip_uri_parse_ipv6(char *scan, char *uend)
11962882Svi117747 {
11972882Svi117747 	char		*mark;
11982882Svi117747 	unsigned	j = 0;			/* index for addr */
11992882Svi117747 	unsigned	val = 0;		/* hex value */
12002882Svi117747 	int		zpad = 0;		/* index of :: delimiter */
12012882Svi117747 
12022882Svi117747 	if (*scan != '[')
12032882Svi117747 		return (0);
12042882Svi117747 	++scan;
12052882Svi117747 	j = 0;
12062882Svi117747 
12072882Svi117747 	/*
12082882Svi117747 	 * check for leading "::", set zpad to the position of the "::"
12092882Svi117747 	 */
12102882Svi117747 	if (scan + 1 < uend && scan[0] == ':' && scan[1] == ':') {
12112882Svi117747 		zpad = 0;
12122882Svi117747 		scan += 2;
12132882Svi117747 	} else {
12142882Svi117747 		zpad = -1;
12152882Svi117747 	}
12162882Svi117747 
12172882Svi117747 	/*
12182882Svi117747 	 * loop through up to 16 bytes of IPv6 address
12192882Svi117747 	 */
12202882Svi117747 	while (scan < uend && j < 15) {
12212882Svi117747 		if (!SIP_URI_ISHEX(*scan))
12222882Svi117747 			break;
12232882Svi117747 		mark = scan;
12242882Svi117747 		val = SIP_URI_HEXVAL(*scan);
12252882Svi117747 		while (++scan < uend && SIP_URI_ISHEX(*scan)) {
12262882Svi117747 			val = val * 16 + SIP_URI_HEXVAL(*scan);
12272882Svi117747 			if (val > 0xffff)
12282882Svi117747 				return (0);
12292882Svi117747 		}
12302882Svi117747 
12312882Svi117747 		/*
12322882Svi117747 		 * always require a delimiter or ]
12332882Svi117747 		 */
12342882Svi117747 		if (scan == uend)
12352882Svi117747 			return (0);
12362882Svi117747 
12372882Svi117747 		if (*scan == '.' && (j == 12 || (zpad != -1 && j < 12)) &&
12382882Svi117747 		    mark < uend && sip_uri_parse_ipv4(mark, uend - 1) &&
12392882Svi117747 		    *(uend - 1) == ']') {
12402882Svi117747 			mark = uend - 1;
12412882Svi117747 			j += 4;
12422882Svi117747 			scan = mark + 1;
12432882Svi117747 			break;
12442882Svi117747 		}
12452882Svi117747 
12462882Svi117747 		/*
12472882Svi117747 		 * set address
12482882Svi117747 		 */
12492882Svi117747 		j += 2;
12502882Svi117747 
12512882Svi117747 		/*
12522882Svi117747 		 * check for delimiter or ]
12532882Svi117747 		 */
12542882Svi117747 		if (*scan == ':') {
12552882Svi117747 			/*
12562882Svi117747 			 * found ":" delimiter, check for "::"
12572882Svi117747 			 */
12582882Svi117747 			if (++scan < uend && *scan == ':') {
12592882Svi117747 				if (zpad != -1)
12602882Svi117747 					return (0);
12612882Svi117747 				zpad = j;
12622882Svi117747 				if (++scan < uend && *scan == ']') {
12632882Svi117747 					++scan;
12642882Svi117747 					break;
12652882Svi117747 				}
12662882Svi117747 			}
12672882Svi117747 		} else if (*scan == ']' && (j == 16 || zpad != -1)) {
12682882Svi117747 			++scan;
12692882Svi117747 			break;
12702882Svi117747 		} else {
12712882Svi117747 			/*
12722882Svi117747 			 * not a valid delimiter
12732882Svi117747 			 */
12742882Svi117747 			return (0);
12752882Svi117747 		}
12762882Svi117747 	}
12772882Svi117747 	if (zpad == -1 && j < 16)
12782882Svi117747 		return (0);
12792882Svi117747 	if (zpad != -1) {
12802882Svi117747 		if (j > 15)
12812882Svi117747 			return (0);
12822882Svi117747 	}
12832882Svi117747 
12842882Svi117747 	if (scan == uend)
12852882Svi117747 		return (1);
12862882Svi117747 
12872882Svi117747 	return (0);
12882882Svi117747 }
12892882Svi117747 
12902882Svi117747 /*
12912882Svi117747  * hostname         =  *( domainlabel "." ) toplabel [ "." ]
12922882Svi117747  * domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
12932882Svi117747  * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
12942882Svi117747  */
12952882Svi117747 static int
sip_uri_parse_hostname(char * scan,char * uend)12962882Svi117747 sip_uri_parse_hostname(char *scan, char *uend)
12972882Svi117747 {
12982882Svi117747 	int	sawalpha = 0;
12992882Svi117747 
13002882Svi117747 	if (scan < uend && SIP_URI_ISALNUM(*scan)) {
13012882Svi117747 		do {
13022882Svi117747 			sawalpha = SIP_URI_ISALPHA(*scan);
13032882Svi117747 			while (SIP_URI_ISHOST(*scan))
13042882Svi117747 				++scan;
13052882Svi117747 			if (*scan != '.')
13062882Svi117747 				break;
13072882Svi117747 			++scan;
13082882Svi117747 		} while (scan < uend && SIP_URI_ISALNUM(*scan));
13092882Svi117747 	}
13102882Svi117747 
13112882Svi117747 	if (sawalpha && scan == uend)
13122882Svi117747 		return (1);
13132882Svi117747 	return (0);
13142882Svi117747 }
13152882Svi117747 
13162882Svi117747 
13172882Svi117747 /*
13182882Svi117747  * parse the network path portion of a full URL
13192882Svi117747  */
13202882Svi117747 static void
sip_uri_parse_netpath(_sip_uri_t * outurl,char ** pscan,char * uend,boolean_t issip)13212882Svi117747 sip_uri_parse_netpath(_sip_uri_t *outurl, char **pscan, char *uend,
13222882Svi117747     boolean_t issip)
13232882Svi117747 {
13242882Svi117747 	char	*mark = (char *)0;
13252882Svi117747 	char	*mark2 = (char *)0;
13262882Svi117747 	char	*scan = *pscan;
13272882Svi117747 	int	gothost = 0;
13282882Svi117747 
13292882Svi117747 	/*
13302882Svi117747 	 * look for the first high-level delimiter
13312882Svi117747 	 */
13322882Svi117747 	mark = scan;
13332882Svi117747 	while (scan < uend && *scan != '@')
13342882Svi117747 		++scan;
13352882Svi117747 	/*
13362882Svi117747 	 * handle userinfo section of URL
13372882Svi117747 	 */
13382882Svi117747 	if (scan < uend && *scan == '@') {
13392882Svi117747 		/*
13402882Svi117747 		 * parse user
13412882Svi117747 		 */
13422882Svi117747 		mark2 = mark;
13432882Svi117747 		while (mark < scan && *mark != ':')
13442882Svi117747 			++mark;
13452882Svi117747 		sip_uri_parse_user(outurl, mark2, mark);
13462882Svi117747 		/*
13472882Svi117747 		 * parse password
13482882Svi117747 		 */
13492882Svi117747 		if (*mark == ':')
13502882Svi117747 			sip_uri_parse_password(outurl, mark, scan);
13512882Svi117747 		mark = ++scan;
13522882Svi117747 	}
13532882Svi117747 
13542882Svi117747 	scan = mark;
13552882Svi117747 	if (scan < uend && *scan == '[') {	/* look for an IPv6 address */
13562882Svi117747 		while (scan < uend && *scan != ']')
13572882Svi117747 			++scan;
13582882Svi117747 		if (scan < uend) {
13592882Svi117747 			++scan;
13602882Svi117747 			if (sip_uri_parse_ipv6(mark, scan))
13612882Svi117747 				gothost = 1;
13622882Svi117747 		}
13632882Svi117747 	} else {
13642882Svi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPHDELIM(*scan)) ||
13652882Svi117747 		    (!issip && !SIP_URI_ISABSHDELIM(*scan)))) {
13662882Svi117747 			++scan;
13672882Svi117747 		}
13682882Svi117747 
13692882Svi117747 		/*
13702882Svi117747 		 * look for an IPv4 address
13712882Svi117747 		 */
13722882Svi117747 		if (mark < scan && SIP_URI_ISDIGIT(*mark) &&
13732882Svi117747 		    sip_uri_parse_ipv4(mark, scan)) {
13742882Svi117747 			gothost = 1;
13752882Svi117747 		}
13762882Svi117747 
13772882Svi117747 		/*
13782882Svi117747 		 * look for a valid host name
13792882Svi117747 		 */
13802882Svi117747 		if (!gothost && mark < scan &&
13812882Svi117747 		    sip_uri_parse_hostname(mark, scan)) {
13822882Svi117747 			gothost = 1;
13832882Svi117747 		}
13842882Svi117747 	}
13852882Svi117747 	/*
13862882Svi117747 	 * handle invalid host name
13872882Svi117747 	 */
13882882Svi117747 	if (!gothost)
13892882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_HOST;
13902882Svi117747 	/*
13912882Svi117747 	 * save host name
13922882Svi117747 	 */
13932882Svi117747 	outurl->sip_uri_host.sip_str_ptr = mark;
13942882Svi117747 	outurl->sip_uri_host.sip_str_len = scan - mark;
13952882Svi117747 
13962882Svi117747 	mark = scan;
13972882Svi117747 	/*
13982882Svi117747 	 * parse the port number
13992882Svi117747 	 */
14002882Svi117747 	if (scan < uend && *scan == ':') {
14012882Svi117747 		while (scan < uend && ((issip && !SIP_URI_ISSIPDELIM(*scan)) ||
14022882Svi117747 		    (!issip && !SIP_URI_ISABSDELIM(*scan)))) {
14032882Svi117747 			++scan;
14042882Svi117747 		}
14052882Svi117747 		sip_uri_parse_port(outurl, mark, scan);
14062882Svi117747 	}
14072882Svi117747 
14082882Svi117747 	/*
14092882Svi117747 	 * set return pointer
14102882Svi117747 	 */
14112882Svi117747 	*pscan = scan;
14122882Svi117747 }
14132882Svi117747 
14142882Svi117747 /*
14152882Svi117747  * parse a URL
14162882Svi117747  * URL = SIP-URI / SIPS-URI / absoluteURI
14172882Svi117747  */
14182882Svi117747 void
sip_uri_parse_it(_sip_uri_t * outurl,sip_str_t * uri_str)14192882Svi117747 sip_uri_parse_it(_sip_uri_t *outurl, sip_str_t *uri_str)
14202882Svi117747 {
14212882Svi117747 	char 		*mark;
14222882Svi117747 	char		*scan;
14232882Svi117747 	char		*uend;
14242882Svi117747 	char		*str = uri_str->sip_str_ptr;
14252882Svi117747 	unsigned	urlen = uri_str->sip_str_len;
14262882Svi117747 
14272882Svi117747 	/*
14282882Svi117747 	 * reset output parameters
14292882Svi117747 	 */
14302882Svi117747 	(void) memset(outurl, 0, sizeof (sip_uri_t));
14312882Svi117747 
14322882Svi117747 	/*
14332882Svi117747 	 * strip enclosing angle brackets
14342882Svi117747 	 */
14352882Svi117747 	if (urlen > 1 && str[0] == '<' && str[urlen-1] == '>') {
14362882Svi117747 		urlen -= 2;
14372882Svi117747 		++str;
14382882Svi117747 	}
14392882Svi117747 	uend = str + urlen;
14402882Svi117747 
14412882Svi117747 	/*
14422882Svi117747 	 * strip off space prefix and trailing spaces
14432882Svi117747 	 */
14442882Svi117747 	while (str < uend && isspace(*str)) {
14452882Svi117747 		++str;
14462882Svi117747 		--urlen;
14472882Svi117747 	}
14482882Svi117747 	while (str < uend && isspace(*(uend - 1))) {
14492882Svi117747 		--uend;
14502882Svi117747 		--urlen;
14512882Svi117747 	}
14522882Svi117747 
14532882Svi117747 	/*
14542882Svi117747 	 * strip off "URL:" prefix
14552882Svi117747 	 */
14562882Svi117747 	if (urlen > 4 && sip_uri_url_casecmp(str, "URL:", 4) == 0) {
14572882Svi117747 		str += 4;
14582882Svi117747 		urlen -= 4;
14592882Svi117747 	}
14602882Svi117747 
14612882Svi117747 	/*
14622882Svi117747 	 * parse the scheme name
14632882Svi117747 	 */
14642882Svi117747 	mark = scan = str;
14652882Svi117747 	while (scan < uend && *scan != ':')
14662882Svi117747 		++scan;
14672882Svi117747 	if (scan == uend || !sip_uri_parse_scheme(outurl, mark, scan)) {
14682882Svi117747 		outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
14692882Svi117747 		return;
14702882Svi117747 	}
14712882Svi117747 
14722882Svi117747 	if ((outurl->sip_uri_scheme.sip_str_len == SIP_SCHEME_LEN &&
14732882Svi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIP_SCHEME,
14742882Svi117747 	    SIP_SCHEME_LEN)) ||
14752882Svi117747 	    (outurl->sip_uri_scheme.sip_str_len == SIPS_SCHEME_LEN &&
14762882Svi117747 	    !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIPS_SCHEME,
14772882Svi117747 	    SIPS_SCHEME_LEN))) {
14782882Svi117747 		outurl->sip_uri_issip = B_TRUE;
14792882Svi117747 	} else {
14802882Svi117747 		outurl->sip_uri_issip = B_FALSE;
14812882Svi117747 	}
14822882Svi117747 	++scan; /* skip ':' */
14832882Svi117747 
14842882Svi117747 	if (outurl->sip_uri_issip) {
14852882Svi117747 		/*
14862882Svi117747 		 * parse SIP URL
14872882Svi117747 		 */
14882882Svi117747 		sip_uri_parse_netpath(outurl, &scan, uend, B_TRUE);
14892882Svi117747 
14902882Svi117747 		/*
14912882Svi117747 		 * parse parameters
14922882Svi117747 		 */
14932882Svi117747 		if (scan < uend && *scan == ';') {
14942882Svi117747 			mark = scan;
14952882Svi117747 			while (scan < uend && *scan != '?')
14962882Svi117747 				++scan;
14972882Svi117747 			sip_uri_parse_params(outurl, mark, scan);
14982882Svi117747 		}
14992882Svi117747 
15002882Svi117747 		/*
15012882Svi117747 		 * parse headers
15022882Svi117747 		 */
15032882Svi117747 		if (scan < uend && *scan == '?')
15042882Svi117747 			sip_uri_parse_headers(outurl, scan, uend);
15052882Svi117747 	} else if (scan < uend && scan[0] == '/') {	 /* parse absoluteURL */
15062882Svi117747 		++scan;
15072882Svi117747 		/*
15082882Svi117747 		 * parse authority
15092882Svi117747 		 * authority	= srvr / reg-name
15102882Svi117747 		 * srvr		= [ [ userinfo "@" ] hostport ]
15112882Svi117747 		 * reg-name	= 1*(unreserved / escaped / "$" / ","
15122882Svi117747 		 *			/ ";" / ":" / "@" / "&" / "=" / "+")
15132882Svi117747 		 */
15142882Svi117747 		if (scan < uend && *scan == '/') {
15152882Svi117747 			++scan;
15162882Svi117747 			mark = scan;
15172882Svi117747 			/*
15182882Svi117747 			 * take authority as srvr
15192882Svi117747 			 */
15202882Svi117747 			sip_uri_parse_netpath(outurl, &scan, uend, B_FALSE);
15212882Svi117747 
15222882Svi117747 			/*
15232882Svi117747 			 * if srvr failed, take it as reg-name
15242882Svi117747 			 * parse reg-name
15252882Svi117747 			 */
15262882Svi117747 			if (outurl->sip_uri_errflags & SIP_URIERR_USER ||
15272882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PASS ||
15282882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_HOST ||
15292882Svi117747 			    outurl->sip_uri_errflags & SIP_URIERR_PORT) {
15302882Svi117747 				scan = mark;
15312882Svi117747 				while (scan < uend && *scan != '/' &&
15322882Svi117747 					*scan != '?') {
15332882Svi117747 					++scan;
15342882Svi117747 				}
15352882Svi117747 				sip_uri_parse_abs_regname(outurl, mark, scan);
15362882Svi117747 				if (!(outurl->sip_uri_errflags &
15372882Svi117747 				    SIP_URIERR_REGNAME)) {
15382882Svi117747 					/*
15392882Svi117747 					 * remove error info of user,
15402882Svi117747 					 * password, host, port
15412882Svi117747 					 */
15422882Svi117747 					outurl->sip_uri_user.sip_str_ptr = NULL;
15432882Svi117747 					outurl->sip_uri_user.sip_str_len = 0;
15442882Svi117747 					outurl->sip_uri_errflags &=
15452882Svi117747 					    ~SIP_URIERR_USER;
15462882Svi117747 					outurl->sip_uri_password.sip_str_ptr =
15472882Svi117747 					    NULL;
15482882Svi117747 					outurl->sip_uri_password.sip_str_len =
15492882Svi117747 					    0;
15502882Svi117747 					outurl->sip_uri_errflags &=
15512882Svi117747 					    ~SIP_URIERR_PASS;
15522882Svi117747 					outurl->sip_uri_host.sip_str_ptr = NULL;
15532882Svi117747 					outurl->sip_uri_host.sip_str_len = 0;
15542882Svi117747 					outurl->sip_uri_errflags &=
15552882Svi117747 					    ~SIP_URIERR_HOST;
15562882Svi117747 					outurl->sip_uri_port = 0;
15572882Svi117747 					outurl->sip_uri_errflags &=
15582882Svi117747 					    ~SIP_URIERR_PORT;
15592882Svi117747 				}
15602882Svi117747 			}
15612882Svi117747 		} else {
15622882Svi117747 			/*
15632882Svi117747 			 * there is no net-path
15642882Svi117747 			 */
15652882Svi117747 			--scan;
15662882Svi117747 		}
15672882Svi117747 		/*
15682882Svi117747 		 * parse abs-path
15692882Svi117747 		 */
15702882Svi117747 		if (scan < uend && *scan == '/') {
15712882Svi117747 			mark = scan;
15722882Svi117747 			while (scan < uend && *scan != '?')
15732882Svi117747 				++scan;
15742882Svi117747 			sip_uri_parse_abs_path(outurl, mark, scan);
15752882Svi117747 		}
15762882Svi117747 
15772882Svi117747 		/*
15782882Svi117747 		 * parse query
15792882Svi117747 		 */
15802882Svi117747 		if (scan < uend && *scan == '?')
15812882Svi117747 			sip_uri_parse_abs_query(outurl, scan, uend);
15822882Svi117747 	} else {
15832882Svi117747 		/*
15842882Svi117747 		 * parse opaque-part
15852882Svi117747 		 */
15862882Svi117747 		sip_uri_parse_abs_opaque(outurl, scan, uend);
15872882Svi117747 	}
15882882Svi117747 }
1589