summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--channels/chan_sip.c15
-rw-r--r--channels/sip/reqresp_parser.c101
3 files changed, 119 insertions, 8 deletions
diff --git a/CHANGES b/CHANGES
index f5f652448..8c3a25347 100644
--- a/CHANGES
+++ b/CHANGES
@@ -86,6 +86,17 @@ MixMonitor
* A new function, MIXMONITOR, has been added to allow access to individual
instances of MixMonitor on a channel.
+
+Channel Drivers
+-------------------------
+
+chan_sip
+-------------------------
+ * TEL URI support for inbound INVITE requests has been added. chan_sip will
+ now handle TEL schemes in the Request and From URIs. The phone-context in
+ the Request URI will be stored in the TELPHONECONTEXT channel variable on
+ the inbound channel.
+
Debugging
-------------------------
* Core Show Locks output now includes Thread/LWP ID if the platform
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 68d07a63c..24a9370a7 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -17691,7 +17691,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
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;
}
@@ -17719,7 +17719,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
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;
}
@@ -18607,10 +18607,13 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
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)
@@ -18625,7 +18628,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
/* 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");
}
diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c
index 7d4445784..5c2f2eb1f 100644
--- a/channels/sip/reqresp_parser.c
+++ b/channels/sip/reqresp_parser.c
@@ -45,6 +45,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
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
@@ -79,6 +80,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
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;
}
@@ -93,6 +95,42 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
/* 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, '@'))) {
@@ -375,6 +413,51 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
.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);
@@ -386,7 +469,9 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
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:
@@ -407,7 +492,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test)
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,
&params,
&headers,
@@ -460,6 +545,7 @@ AST_TEST_DEFINE(sip_parse_uri_test)
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:
@@ -588,6 +674,17 @@ AST_TEST_DEFINE(sip_parse_uri_test)
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;
}