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
SIP_URI_HEXVAL(int c)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
sip_uri_url_casecmp(const char * str1,const char * str2,unsigned len)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
sip_uri_parse_tel(char * scan,char * uend)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
sip_uri_parse_tel_areaspe(char * scan,char * uend)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
sip_uri_hexVal(char * scan,char * uend)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
sip_uri_parse_tel_servicepro(char * scan,char * uend)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
sip_uri_parse_tel_futureext(char * scan,char * uend)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
sip_uri_isTokenchar(char ** pscan,char * uend)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
sip_uri_isEscapedPound(char ** pscan,char * uend)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
sip_uri_parse_scheme(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_params(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_headers(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_abs_opaque(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_abs_query(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_abs_path(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_abs_regname(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_password(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_user(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_port(_sip_uri_t * outurl,char * scan,char * uend)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
sip_uri_parse_ipv4(char * scan,char * uend)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
sip_uri_parse_ipv6(char * scan,char * uend)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
sip_uri_parse_hostname(char * scan,char * uend)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
sip_uri_parse_netpath(_sip_uri_t * outurl,char ** pscan,char * uend,boolean_t issip)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
sip_uri_parse_it(_sip_uri_t * outurl,sip_str_t * uri_str)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