uri = ast_strdupa(get_in_brackets(tmp));
- if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &unused_password, &domain, NULL)) {
+ if (parse_uri_legacy_check(uri, "sip:,sips:,tel:", &uri, &unused_password, &domain, NULL)) {
ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
return SIP_GET_DEST_INVALID_URI;
}
ast_copy_string(tmpf, sip_get_header(req, "From"), sizeof(tmpf));
if (!ast_strlen_zero(tmpf)) {
from = get_in_brackets(tmpf);
- if (parse_uri_legacy_check(from, "sip:,sips:", &from, NULL, &domain, NULL)) {
+ if (parse_uri_legacy_check(from, "sip:,sips:,tel:", &from, NULL, &domain, NULL)) {
ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from);
return SIP_GET_DEST_INVALID_URI;
}
if (ast_strlen_zero(p->exten)) {
char *t = uri2;
- if (!strncasecmp(t, "sip:", 4))
- t+= 4;
- else if (!strncasecmp(t, "sips:", 5))
+ if (!strncasecmp(t, "sip:", 4)) {
+ t += 4;
+ } else if (!strncasecmp(t, "sips:", 5)) {
t += 5;
+ } else if (!strncasecmp(t, "tel:", 4)) { /* TEL URI INVITE */
+ t += 4;
+ }
ast_string_field_set(p, exten, t);
t = strchr(p->exten, '@');
if (t)
/* save the URI part of the From header */
ast_string_field_set(p, from, of);
- if (parse_uri_legacy_check(of, "sip:,sips:", &name, &unused_password, &domain, NULL)) {
+ if (parse_uri_legacy_check(of, "sip:,sips:,tel:", &name, &unused_password, &domain, NULL)) {
ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
}
char *endparams = NULL;
char *c = NULL;
int error = 0;
+ int teluri_scheme = 0;
/*
* Initialize requested strings - some functions don't care if parse_uri fails
for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
l = strlen(cur);
if (!strncasecmp(uri, cur, l)) {
+ teluri_scheme = !strncasecmp(uri, "tel:", 4); /* TEL URI */
uri += l;
break;
}
/* if we don't want to split around hostport, keep everything as a
* userinfo - cos thats how old parse_uri operated*/
userinfo = uri;
+ } else if (teluri_scheme) {
+ /*
+ * tel: TEL URI INVITE RFC 3966 patch
+ * See http://www.ietf.org/rfc/rfc3966.txt
+ *
+ * Once the full RFC 3966 parsing is implemented,
+ * the ext= or isub= parameters would be extracted from userinfo.
+ * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
+ * Those parameters would be used for ISDN or PSTN local extensions.
+ *
+ * Current restrictions:
+ * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
+ */
+
+ if ((c = strstr(uri, ";phone-context="))) {
+ /*
+ * Local number with context or domain.
+ * ext= or isub= TEL URI parameters should be upfront.
+ * All other parameters should come after the ";phone-context=" parameter.
+ * If other parameters would occur before ";phone-context=" they will be ignored.
+ */
+
+ *c = '\0';
+ userinfo = uri;
+ uri = c + 15;
+ *hostport = uri;
+ } else if ('+' == uri[0]) {
+ /* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
+
+ userinfo = uri;
+ *hostport = uri;
+ } else {
+ ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
+ userinfo = uri; /* Return local number anyway */
+ error = -1;
+ }
} else {
char *dom = "";
if ((c = strchr(uri, '@'))) {
.params.user = ""
};
+ /* RFC 3966 TEL URI INVITE */
+ struct testdata td11 = {
+ .desc = "tel local number",
+ .uri = "tel:0987654321;phone-context=+32987654321",
+ .user = "0987654321",
+ .pass = "",
+ .hostport = "+32987654321",
+ .headers = "",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td12 = {
+ .desc = "tel global number",
+ .uri = "tel:+32987654321",
+ .user = "+32987654321",
+ .pass = "",
+ .hostport = "+32987654321",
+ .headers = "",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ /*
+ * Once the full RFC 3966 parsing is implemented,
+ * only the ext= or isub= parameters would be extracted from .user
+ * Then the ;param=discard would be ignored,
+ * and the .user would only contain "0987654321"
+ */
+ struct testdata td13 = {
+ .desc = "tel local number",
+ .uri = "tel:0987654321;ext=1234;param=discard;phone-context=+32987654321;transport=udp;param2=discard2?header=blah&header2=blah2;param3=residue",
+ .user = "0987654321;ext=1234;param=discard",
+ .pass = "",
+ .hostport = "+32987654321",
+ .headers = "header=blah&header2=blah2",
+ .residue = "param3=residue",
+ .params.transport = "udp",
+ .params.lr = 0,
+ .params.user = ""
+ };
AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
-
+ AST_LIST_INSERT_TAIL(&testdatalist, &td11, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td12, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td13, list);
switch (cmd) {
case TEST_INIT:
params.lr = 0;
ast_copy_string(uri,testdataptr->uri,sizeof(uri));
- if (parse_uri_full(uri, "sip:,sips:", &user,
+ if (parse_uri_full(uri, "sip:,sips:,tel:", &user,
&pass, &hostport,
¶ms,
&headers,
char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
char uri11[] = "host";
+ char uri12[] = "tel:911"; /* TEL URI Local number without context or global number */
switch (cmd) {
case TEST_INIT:
res = AST_TEST_FAIL;
}
+ /* Test 12, simple URI */
+ name = pass = hostport = transport = NULL;
+ if (!parse_uri(uri12, "sip:,sips:,tel:", &name, &pass, &hostport, &transport) ||
+ strcmp(name, "911") || /* We return local number anyway */
+ !ast_strlen_zero(pass) ||
+ !ast_strlen_zero(hostport) || /* No global number nor context */
+ !ast_strlen_zero(transport)) {
+ ast_test_status_update(test, "Test 12: TEL URI INVITE failed.\n");
+ res = AST_TEST_FAIL;
+ }
+
return res;
}