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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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