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