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