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