diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | channels/chan_sip.c | 15 | ||||
-rw-r--r-- | channels/sip/reqresp_parser.c | 101 |
3 files changed, 119 insertions, 8 deletions
@@ -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, ¶ms, &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; } |