[asterisk-commits] rmudgett: branch rmudgett/call_waiting r256605 - in /team/rmudgett/call_waiti...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 9 14:10:08 CDT 2010
Author: rmudgett
Date: Fri Apr 9 14:10:03 2010
New Revision: 256605
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=256605
Log:
Merged revisions 256601-256602 via svnmerge from
https://origsvn.digium.com/svn/asterisk/team/group/CCSS
................
r256601 | rmudgett | 2010-04-09 13:10:20 -0500 (Fri, 09 Apr 2010) | 1 line
Update to trunk merge of CCSS.
................
r256602 | rmudgett | 2010-04-09 13:17:30 -0500 (Fri, 09 Apr 2010) | 35 lines
Merged revisions 256529-256530,256569 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
........
r256529 | mmichelson | 2010-04-09 10:56:55 -0500 (Fri, 09 Apr 2010) | 3 lines
Fix some compiler errors that popped up after the CCSS merge.
........
r256530 | mmichelson | 2010-04-09 11:04:16 -0500 (Fri, 09 Apr 2010) | 21 lines
Add routines for parsing SIP URIs consistently.
From the original issue report opened by Nick Lewis:
Many sip headers in many sip methods contain the ABNF structure
name-andor-addr = name-addr / addr-spec
Examples include the to-header, from-header, contact-header, replyto-header
At the moment chan_sip.c makes various different attempts to parse this name-andor-addr structure for each header type and for each sip method with sometimes limited degrees of success.
I recommend that this name-andor-addr structure be parsed by a dedicated function and that it be used irrespective of the specific method or header that contains the name-andor-addr structure
Nick has also included unit tests for verifying these routines as well, so...heck yeah.
(closes issue #16708)
Reported by: Nick_Lewis
Patches:
reqresp_parser-nameandoraddr2.patch uploaded by Nick Lewis (license 657
Review: https://reviewboard.asterisk.org/r/549
........
r256569 | rmudgett | 2010-04-09 11:43:30 -0500 (Fri, 09 Apr 2010) | 1 line
Remove PRI CCSS BUGBUG message and update configure script.
........
................
Modified:
team/rmudgett/call_waiting/ (props changed)
team/rmudgett/call_waiting/channels/chan_sip.c
team/rmudgett/call_waiting/channels/sig_pri.h
team/rmudgett/call_waiting/channels/sip/include/reqresp_parser.h
team/rmudgett/call_waiting/channels/sip/include/sip.h
team/rmudgett/call_waiting/channels/sip/reqresp_parser.c
team/rmudgett/call_waiting/configure
team/rmudgett/call_waiting/funcs/func_srv.c
team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in
team/rmudgett/call_waiting/tests/test_gosub.c
Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
automerge = *
Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
--- call_waiting-integrated (original)
+++ call_waiting-integrated Fri Apr 9 14:10:03 2010
@@ -1,1 +1,1 @@
-/team/group/CCSS:1-256511
+/team/group/CCSS:1-256603
Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Fri Apr 9 14:10:03 2010
@@ -1,1 +1,1 @@
-/trunk:1-256505
+/trunk:1-256601
Modified: team/rmudgett/call_waiting/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/chan_sip.c?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/channels/chan_sip.c (original)
+++ team/rmudgett/call_waiting/channels/chan_sip.c Fri Apr 9 14:10:03 2010
@@ -1920,7 +1920,7 @@
ast_get_ccnr_available_timer(monitor->interface->config_params);
sip_pvt_lock(monitor_instance->subscription_pvt);
- create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1);
+ create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1, NULL);
ast_sip_ouraddrfor(&monitor_instance->subscription_pvt->sa.sin_addr, &monitor_instance->subscription_pvt->ourip, monitor_instance->subscription_pvt);
monitor_instance->subscription_pvt->subscribed = CALL_COMPLETION;
monitor_instance->subscription_pvt->expiry = when;
@@ -10611,7 +10611,7 @@
sip_pvt_lock(pvt);
- if (create_addr(pvt, epa_entry->destination, NULL, TRUE)) {
+ if (create_addr(pvt, epa_entry->destination, NULL, TRUE, NULL)) {
dialog_unlink_all(pvt, TRUE, TRUE);
dialog_unref(pvt, "create_addr failed in transmit_publish. Unref dialog");
}
Modified: team/rmudgett/call_waiting/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/sig_pri.h?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/channels/sig_pri.h (original)
+++ team/rmudgett/call_waiting/channels/sig_pri.h Fri Apr 9 14:10:03 2010
@@ -30,10 +30,6 @@
#include "asterisk/ccss.h"
#include <libpri.h>
#include <dahdi/user.h>
-#if defined(PRI_SUBCMD_CC_AVAILABLE)
-/* BUGBUG the HAVE_PRI_CCSS line is to be removed when the CCSS branch is merged to trunk and the configure script is updated. */
-#define HAVE_PRI_CCSS 1
-#endif /* defined(PRI_SUBCMD_CC_AVAILABLE) */
#if defined(PRI_EVENT_CONNECT_ACK)
/* BUGBUG the HAVE_PRI_CALL_WAITING line is to be removed when the call_waiting branch is merged to trunk and the configure script is updated. */
#define HAVE_PRI_CALL_WAITING 1
Modified: team/rmudgett/call_waiting/channels/sip/include/reqresp_parser.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/sip/include/reqresp_parser.h?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/channels/sip/include/reqresp_parser.h (original)
+++ team/rmudgett/call_waiting/channels/sip/include/reqresp_parser.h Fri Apr 9 14:10:03 2010
@@ -45,6 +45,15 @@
int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass, char **domain, char **port, char **transport);
/*!
+ * \brief parses a URI in to all of its components and any trailing residue
+ *
+ * \retval 0 on success
+ * \retval -1 on error.
+ *
+ */
+int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue);
+
+/*!
* \brief Get caller id name from SIP headers, copy into output buffer
*
* \retval input string pointer placed after display-name field if possible
@@ -76,6 +85,33 @@
*/
char *get_in_brackets(char *tmp);
+/*! \brief Get text in brackets and any trailing residue
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ * \retval 1 no brackets so got all
+ */
+int get_in_brackets_full(char *tmp, char **out, char **residue);
+
+/*! \brief Parse the ABNF structure
+ * name-andor-addr = name-addr / addr-spec
+ * into its components and return any trailing message-header parameters
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **remander);
+
+/*! \brief Parse all contact header contacts
+ * \retval 0 success
+ * \retval -1 failure
+ * \retval 1 all contacts (star)
+ */
+
+int get_comma(char *parse, char **out);
+
+int parse_contact_header(char *contactheader, struct contactliststruct *contactlist);
+
/*!
* \brief register request parsing tests
*/
Modified: team/rmudgett/call_waiting/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/sip/include/sip.h?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/channels/sip/include/sip.h (original)
+++ team/rmudgett/call_waiting/channels/sip/include/sip.h Fri Apr 9 14:10:03 2010
@@ -1647,4 +1647,34 @@
struct sip_epa_entry *suspension_entry;
};
+/*!
+ * \brief uri parameters
+ *
+ */
+
+struct uriparams {
+ char *transport;
+ char *user;
+ char *method;
+ char *ttl;
+ char *maddr;
+ int lr;
+};
+
+struct contact {
+ AST_LIST_ENTRY(contact) list;
+ char *name;
+ char *user;
+ char *pass;
+ char *host;
+ char *port;
+ struct uriparams params;
+ char *headers;
+ char *expires;
+ char *q;
+};
+
+AST_LIST_HEAD_NOLOCK(contactliststruct, contact);
+
+
#endif
Modified: team/rmudgett/call_waiting/channels/sip/reqresp_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/sip/reqresp_parser.c?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/channels/sip/reqresp_parser.c (original)
+++ team/rmudgett/call_waiting/channels/sip/reqresp_parser.c Fri Apr 9 14:10:03 2010
@@ -28,10 +28,12 @@
#include "include/reqresp_parser.h"
/*! \brief * parses a URI in its components.*/
-int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass, char **domain, char **port, char **transport)
+int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue)
{
- char *name = NULL;
- char *tmp; /* used as temporary place holder */
+ char *userinfo = NULL;
+ char *parameters = NULL;
+ char *endparams = NULL;
+ char *c = NULL;
int error = 0;
/* check for valid input */
@@ -39,16 +41,6 @@
return -1;
}
- /* strip [?headers] from end of uri */
- if ((tmp = strrchr(uri, '?'))) {
- *tmp = '\0';
- }
-
- /* init field as required */
- if (pass)
- *pass = "";
- if (port)
- *port = "";
if (scheme) {
int l;
char *scheme2 = ast_strdupa(scheme);
@@ -65,55 +57,452 @@
error = -1;
}
}
- if (transport) {
- char *t, *type = "";
- *transport = "";
- if ((t = strstr(uri, "transport="))) {
- strsep(&t, "=");
- if ((type = strsep(&t, ";"))) {
- *transport = type;
+
+ if (!host) {
+ /* if we don't want to split around host, keep everything as a userinfo - cos thats how old parse_uri operated*/
+ userinfo = uri;
+ } else {
+ char *hostport;
+ if ((c = strchr(uri, '@'))) {
+ *c++ = '\0';
+ hostport = c;
+ userinfo = uri;
+ uri = hostport; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
+ } else {
+ /* domain-only URI, according to the SIP RFC. */
+ hostport = uri;
+ userinfo = "";
}
- }
- }
-
- if (!domain) {
- /* if we don't want to split around domain, keep everything as a name,
- * so we need to do nothing here, except remember why.
- */
- } else {
- /* store the result in a temp. variable to avoid it being
- * overwritten if arguments point to the same place.
- */
- char *c, *dom = "";
-
- if ((c = strchr(uri, '@')) == NULL) {
- /* domain-only URI, according to the SIP RFC. */
- dom = uri;
- name = "";
- } else {
- *c++ = '\0';
- dom = c;
- name = uri;
- }
-
- /* Remove parameters in domain and name */
- dom = strsep(&dom, ";");
- name = strsep(&name, ";");
-
- if (port && (c = strchr(dom, ':'))) { /* Remove :port */
+
+ if (port && (c = strchr(hostport, ':'))) { /* Remove :port */
*c++ = '\0';
*port = c;
- }
- if (pass && (c = strchr(name, ':'))) { /* user:password */
+ uri = c;
+ } else if (port) {
+ *port = "";
+ }
+
+ *host = hostport;
+ }
+
+ if (pass && (c = strchr(userinfo, ':'))) { /* user:password */
+ *c++ = '\0';
+ *pass = c;
+ } else if (pass) {
+ *pass = "";
+ }
+
+ if (user) {
+ *user = userinfo;
+ }
+
+ parameters = uri;
+ /* strip [?headers] from end of uri - even if no header pointer exists*/
+ if ((c = strrchr(uri, '?'))) {
*c++ = '\0';
- *pass = c;
- }
- *domain = dom;
- }
- if (ret_name) /* same as for domain, store the result only at the end */
- *ret_name = name;
+ uri = c;
+ if (headers) {
+ *headers = c;
+ }
+ if ((c = strrchr(uri, ';'))) {
+ *c++ = '\0';
+ } else {
+ c = strrchr(uri, '\0');
+ }
+ uri = c; /* residue */
+
+
+ } else if (headers) {
+ *headers = "";
+ }
+
+ /* parse parameters */
+ endparams = strchr(parameters,'\0');
+ if ((c = strchr(parameters, ';'))) {
+ *c++ = '\0';
+ parameters = c;
+ } else {
+ parameters = endparams;
+ }
+
+ if (params) {
+ char *rem = parameters; /* unparsed or unrecognised remainder */
+ char *label;
+ char *value;
+ int lr = 0;
+
+ params->transport = "";
+ params->user = "";
+ params->method = "";
+ params->ttl = "";
+ params->maddr = "";
+ params->lr = 0;
+
+ rem = parameters;
+
+ while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
+ /* The while condition will not continue evaluation to set lr if it matches "lr=" */
+ if (lr) {
+ value = parameters;
+ } else {
+ *value++ = '\0';
+ }
+ label = parameters;
+ if ((c = strchr(value, ';'))) {
+ *c++ = '\0';
+ parameters = c;
+ } else {
+ parameters = endparams;
+ }
+
+ if (!strcmp(label, "transport")) {
+ if (params) {params->transport=value;}
+ rem = parameters;
+ } else if (!strcmp(label, "user")) {
+ if (params) {params->user=value;}
+ rem = parameters;
+ } else if (!strcmp(label, "method")) {
+ if (params) {params->method=value;}
+ rem = parameters;
+ } else if (!strcmp(label, "ttl")) {
+ if (params) {params->ttl=value;}
+ rem = parameters;
+ } else if (!strcmp(label, "maddr")) {
+ if (params) {params->maddr=value;}
+ rem = parameters;
+ /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */
+ } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
+ if (params) {params->lr=1;}
+ rem = parameters;
+ } else {
+ value--;
+ *value = '=';
+ if(c) {
+ c--;
+ *c = ';';
+ }
+ }
+ }
+ if (rem > uri) { /* no headers */
+ uri = rem;
+ }
+
+ }
+
+ if (residue) {
+ *residue = uri;
+ }
return error;
+}
+
+
+AST_TEST_DEFINE(sip_parse_uri_fully_test)
+{
+ int res = AST_TEST_PASS;
+ char uri[1024];
+ char *user, *pass, *host, *port, *headers, *residue;
+ struct uriparams params;
+
+ struct testdata {
+ char *desc;
+ char *uri;
+ char **userptr;
+ char **passptr;
+ char **hostptr;
+ char **portptr;
+ char **headersptr;
+ char **residueptr;
+ struct uriparams *paramsptr;
+ char *user;
+ char *pass;
+ char *host;
+ char *port;
+ char *headers;
+ char *residue;
+ struct uriparams params;
+ AST_LIST_ENTRY(testdata) list;
+ };
+
+
+ struct testdata *testdataptr;
+
+ static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
+
+ struct testdata td1 = {
+ .desc = "no headers",
+ .uri = "sip:user:secret at host:5060;param=discard;transport=tcp;param2=residue",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "param2=residue",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td2 = {
+ .desc = "with headers",
+ .uri = "sip:user:secret at host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "header=blah&header2=blah2",
+ .residue = "param3=residue",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td3 = {
+ .desc = "difficult user",
+ .uri = "sip:-_.!~*'()&=+$,;?/:secret at host:5060;transport=tcp",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "-_.!~*'()&=+$,;?/",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td4 = {
+ .desc = "difficult pass",
+ .uri = "sip:user:-_.!~*'()&=+$, at host:5060;transport=tcp",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "-_.!~*'()&=+$,",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td5 = {
+ .desc = "difficult host",
+ .uri = "sip:user:secret at 1-1.a-1.:5060;transport=tcp",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "1-1.a-1.",
+ .port = "5060",
+ .headers = "",
+ .residue = "",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td6 = {
+ .desc = "difficult params near transport",
+ .uri = "sip:user:secret at host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td7 = {
+ .desc = "difficult params near headers",
+ .uri = "sip:user:secret at host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "header=blah&header2=blah2",
+ .residue = "-_.!~*'()[]/:&+$=residue",
+ .params.transport = "",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td8 = {
+ .desc = "lr parameter",
+ .uri = "sip:user:secret at host:5060;param=discard;lr?header=blah",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "header=blah",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 1,
+ .params.user = ""
+ };
+
+ struct testdata td9 = {
+ .desc = "alternative lr parameter",
+ .uri = "sip:user:secret at host:5060;param=discard;lr=yes?header=blah",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "header=blah",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 1,
+ .params.user = ""
+ };
+
+ struct testdata td10 = {
+ .desc = "no lr parameter",
+ .uri = "sip:user:secret at host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "header=blah",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+
+ AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
+
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "sip_uri_full_parse_test";
+ info->category = "channels/chan_sip/";
+ info->summary = "tests sip full uri parsing";
+ info->description =
+ "Tests full parsing of various URIs "
+ "Verifies output matches expected behavior.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
+ user = pass = host = port = headers = residue = NULL;
+ params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
+ params.lr = 0;
+
+ ast_copy_string(uri,testdataptr->uri,sizeof(uri));
+ if (parse_uri_full(uri, "sip:,sips:", testdataptr->userptr, testdataptr->passptr, testdataptr->hostptr, testdataptr->portptr, testdataptr->paramsptr, testdataptr->headersptr, testdataptr->residueptr) ||
+ ((testdataptr->userptr) && strcmp(testdataptr->user, user)) ||
+ ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) ||
+ ((testdataptr->hostptr) && strcmp(testdataptr->host, host)) ||
+ ((testdataptr->portptr) && strcmp(testdataptr->port, port)) ||
+ ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) ||
+ ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) ||
+ ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) ||
+ ((testdataptr->paramsptr) && (testdataptr->params.lr != params.lr)) ||
+ ((testdataptr->paramsptr) && strcmp(testdataptr->params.user,params.user))
+ ) {
+ ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
+ res = AST_TEST_FAIL;
+ }
+ }
+
+
+ return res;
+}
+
+
+int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **host, char **port, char **transport) {
+ int ret;
+ char *headers;
+ struct uriparams params;
+
+ headers = NULL;
+ ret = parse_uri_full(uri, scheme, user, pass, host, port, ¶ms, &headers, NULL);
+ if (transport) {
+ *transport=params.transport;
+ }
+ return ret;
}
AST_TEST_DEFINE(sip_parse_uri_test)
@@ -535,44 +924,82 @@
return res;
}
-char *get_in_brackets(char *tmp)
+int get_in_brackets_full(char *tmp,char **out,char **residue)
{
const char *parse = tmp;
char *first_bracket;
+ char *second_bracket;
+
+ if (out) {
+ *out = "";
+ }
+ if (residue) {
+ *residue = "";
+ }
if (ast_strlen_zero(tmp)) {
- return tmp;
+ return 1;
}
/*
* Skip any quoted text until we find the part in brackets.
- * On any error give up and return the full string.
+ * On any error give up and return -1
*/
while ( (first_bracket = strchr(parse, '<')) ) {
char *first_quote = strchr(parse, '"');
-
- if (!first_quote || first_quote > first_bracket)
+ first_bracket++;
+ if (!first_quote || first_quote >= first_bracket) {
break; /* no need to look at quoted part */
+ }
/* the bracket is within quotes, so ignore it */
parse = find_closing_quote(first_quote + 1, NULL);
if (!*parse) {
ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
- break;
+ return -1;
}
parse++;
}
+
+ /* If no first bracket then still look for a second bracket as some other parsing functions
+ may overwrite first bracket with NULL when terminating a token based display-name. As this
+ only affects token based display-names there is no danger of brackets being in quotes */
if (first_bracket) {
- char *second_bracket = strchr(first_bracket + 1, '>');
- if (second_bracket) {
- *second_bracket = '\0';
- tmp = first_bracket + 1;
+ parse = first_bracket;
} else {
+ parse = tmp;
+ }
+
+ if ((second_bracket = strchr(parse, '>'))) {
+ *second_bracket++ = '\0';
+ if (out) {
+ *out = first_bracket;
+ }
+ if (residue) {
+ *residue = second_bracket;
+ }
+ return 0;
+ }
+
+ if ((first_bracket)) {
ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
- }
- }
-
+ return -1;
+ }
+
+ if (out) {
+ *out = tmp;
+ }
+ return 1;
+}
+
+char *get_in_brackets(char *tmp)
+{
+ char *out;
+ if((get_in_brackets_full(tmp, &out, NULL))) {
return tmp;
+ } else {
+ return out;
+}
}
AST_TEST_DEFINE(get_in_brackets_test)
@@ -645,12 +1072,442 @@
return res;
}
+
+int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **host, char **port, struct uriparams *params, char **headers, char **residue)
+{
+ static char buf[1024];
+ char **residue2=residue;
+ int ret;
+ if (name) {
+ get_calleridname(uri,buf,sizeof(buf));
+ *name = buf;
+ }
+ ret = get_in_brackets_full(uri,&uri,residue);
+ if (ret == 0) { /* uri is in brackets so do not treat unknown trailing uri parameters as potential messageheader parameters */
+ *residue = *residue + 1; /* step over the first semicolon so as per parse uri residue */
+ residue2 = NULL;
+ }
+
+ return parse_uri_full(uri, scheme, user, pass, host, port, params, headers, residue2);
+}
+
+AST_TEST_DEFINE(parse_name_andor_addr_test)
+{
+ int res = AST_TEST_PASS;
+ char uri[1024];
+ char *name, *user, *pass, *host, *port, *headers, *residue;
+ struct uriparams params;
+
+ struct testdata {
+ char *desc;
+ char *uri;
+ char **nameptr;
+ char **userptr;
+ char **passptr;
+ char **hostptr;
+ char **portptr;
+ char **headersptr;
+ char **residueptr;
+ struct uriparams *paramsptr;
+ char *name;
+ char *user;
+ char *pass;
+ char *host;
+ char *port;
+ char *headers;
+ char *residue;
+ struct uriparams params;
+ AST_LIST_ENTRY(testdata) list;
+ };
+
+ struct testdata *testdataptr;
+
+ static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
+
+ struct testdata td1 = {
+ .desc = "quotes and brackets",
+ .uri = "\"name :@ \" <sip:user:secret at host:5060;param=discard;transport=tcp>;tag=tag",
+ .nameptr = &name,
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .name = "name :@ ",
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "tag=tag",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td2 = {
+ .desc = "no quotes",
+ .uri = "givenname familyname <sip:user:secret at host:5060;param=discard;transport=tcp>;expires=3600",
+ .nameptr = &name,
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .name = "givenname familyname",
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "expires=3600",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td3 = {
+ .desc = "no brackets",
+ .uri = "sip:user:secret at host:5060;param=discard;transport=tcp;q=1",
+ .nameptr = &name,
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .name = "",
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5060",
+ .headers = "",
+ .residue = "q=1",
+ .params.transport = "tcp",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+ struct testdata td4 = {
+ .desc = "just host",
+ .uri = "sips:host",
+ .nameptr = &name,
+ .userptr = &user,
+ .passptr = &pass,
+ .hostptr = &host,
+ .portptr = &port,
+ .headersptr = &headers,
+ .residueptr = &residue,
+ .paramsptr = ¶ms,
+ .name = "",
+ .user = "",
+ .pass = "",
+ .host = "host",
+ .port = "",
+ .headers = "",
+ .residue = "",
+ .params.transport = "",
+ .params.lr = 0,
+ .params.user = ""
+ };
+
+
+ AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
+
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "parse_name_andor_addr_test";
+ info->category = "channels/chan_sip/";
+ info->summary = "tests parsing of name_andor_addr abnf structure";
+ info->description =
+ "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
+ "Verifies output matches expected behavior.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
+ name = user = pass = host = port = headers = residue = NULL;
+ params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
+ params.lr = 0;
+ ast_copy_string(uri,testdataptr->uri,sizeof(uri));
+ if (parse_name_andor_addr(uri, "sip:,sips:", testdataptr->nameptr, testdataptr->userptr, testdataptr->passptr, testdataptr->hostptr, testdataptr->portptr, testdataptr->paramsptr, testdataptr->headersptr, testdataptr->residueptr) ||
+ ((testdataptr->nameptr) && strcmp(testdataptr->name, name)) ||
+ ((testdataptr->userptr) && strcmp(testdataptr->user, user)) ||
+ ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) ||
+ ((testdataptr->hostptr) && strcmp(testdataptr->host, host)) ||
+ ((testdataptr->portptr) && strcmp(testdataptr->port, port)) ||
+ ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) ||
+ ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) ||
+ ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) ||
+ ((testdataptr->paramsptr) && strcmp(testdataptr->params.user,params.user))
+ ) {
+ ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
+ res = AST_TEST_FAIL;
+ }
+ }
+
+
+ return res;
+}
+
+int get_comma(char *in, char **out) {
+ char *c;
+ char *parse = in;
+ if (out) {
+ *out = in;
+ }
+
+ /* Skip any quoted text */
+ while (*parse) {
+ if ((c = strchr(parse, '"'))) {
+ in = (char *)find_closing_quote((const char *)c + 1, NULL);
+ if (!*in) {
+ ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
+ return -1;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ parse++;
+ }
+ parse = in;
+
+ /* Skip any userinfo components of a uri as they may contain commas */
+ if ((c = strchr(parse,'@'))) {
+ parse = c+1;
+ }
+ if ((out) && (c = strchr(parse,','))) {
+ *c++ = '\0';
+ *out = c;
+ return 0;
+ }
+ return 1;
+}
+
+int parse_contact_header(char *contactheader, struct contactliststruct *contactlist) {
+ int res;
+ int last;
+ char *comma;
+ char *residue;
+ char *param;
+ char *value;
+ struct contact *contact=NULL;
+
+ if (*contactheader == '*') {
+ return 1;
+ }
+
+ contact = malloc(sizeof(*contact));
+
+ AST_LIST_HEAD_SET_NOLOCK(contactlist, contact);
+ while ((last = get_comma(contactheader,&comma)) != -1) {
+
+ res = parse_name_andor_addr(contactheader,"sip:,sips:",&contact->name,&contact->user,&contact->pass,&contact->host,&contact->port,&contact->params,&contact->headers,&residue);
+ if (res == -1) {
+ return res;
+ }
+
+ /* parse contact params */
+ contact->expires = contact->q = "";
+
+ while ((value = strchr(residue,'='))) {
+ *value++ = '\0';
+
+ param = residue;
+ if ((residue = strchr(value,';'))) {
+ *residue++ = '\0';
+ } else {
+ residue = "";
+ }
+
+ if (!strcmp(param,"expires")) {
+ contact->expires = value;
+ } else if (!strcmp(param,"q")) {
+ contact->q = value;
+ }
+ }
+
+ if(last) {
+ return 0;
+ }
+ contactheader = comma;
+
+ contact = malloc(sizeof(*contact));
+ AST_LIST_INSERT_TAIL(contactlist, contact, list);
+
+ }
+ return last;
+}
+
+AST_TEST_DEFINE(parse_contact_header_test)
+{
+ int res = AST_TEST_PASS;
+ char contactheader[1024];
+ int star;
+ struct contactliststruct contactlist;
+ struct contactliststruct *contactlistptr=&contactlist;
+
+ struct testdata {
+ char *desc;
+ char *contactheader;
+ int star;
+ struct contactliststruct *contactlist;
+
+ AST_LIST_ENTRY(testdata) list;
+ };
+
+ struct testdata *testdataptr;
+ struct contact *tdcontactptr;
+ struct contact *contactptr;
+
+ static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
+ struct contactliststruct contactlist1, contactlist2;
+
+ struct testdata td1 = {
+ .desc = "single contact",
+ .contactheader = "\"name :@;?&,\" <sip:user:secret at host:5082;param=discard;transport=tcp>;expires=3600",
+ .contactlist = &contactlist1,
+ .star = 0
+ };
+ struct contact contact11 = {
+ .name = "name :@;?&,",
+ .user = "user",
+ .pass = "secret",
+ .host = "host",
+ .port = "5082",
+ .params.transport = "tcp",
+ .params.ttl = "",
+ .params.lr = 0,
+ .headers = "",
+ .expires = "3600",
+ .q = ""
+ };
+
+ struct testdata td2 = {
+ .desc = "multiple contacts",
+ .contactheader = "sip:,user1,:,secret1, at host1;ttl=7;q=1;expires=3600,sips:host2",
+ .contactlist = &contactlist2,
+ .star = 0,
+ };
+ struct contact contact21 = {
+ .name = "",
+ .user = ",user1,",
+ .pass = ",secret1,",
+ .host = "host1",
+ .port = "",
+ .params.transport = "",
+ .params.ttl = "7",
+ .params.lr = 0,
+ .headers = "",
+ .expires = "3600",
+ .q = "1"
+ };
+ struct contact contact22 = {
+ .name = "",
+ .user = "",
+ .pass = "",
+ .host = "host2",
+ .port = "",
+ .params.transport = "",
+ .params.ttl = "",
+ .params.lr = 0,
+ .headers = "",
+ .expires = "",
+ .q = ""
+ };
+
+ struct testdata td3 = {
+ .desc = "star - all contacts",
+ .contactheader = "*",
+ .star = 1,
+ .contactlist = NULL
+ };
+
+ AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
+
+ AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
+
+ AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
+ AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
+
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "parse_contact_header_test";
+ info->category = "channels/chan_sip/";
+ info->summary = "tests parsing of sip contact header";
+ info->description =
+ "Tests parsing of a contact header including those with multiple contacts "
+ "Verifies output matches expected behavior.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
+ ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
+ star = parse_contact_header(contactheader,contactlistptr);
+ if (testdataptr->star) {
+ /* expecting star rather than list of contacts */
+ if (!star) {
+ ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
+ res = AST_TEST_FAIL;
+ break;
+ }
+ } else {
+ contactptr = AST_LIST_FIRST(contactlistptr);
+ AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
+ if (!contactptr ||
+ strcmp(tdcontactptr->name, contactptr->name) ||
+ strcmp(tdcontactptr->user, contactptr->user) ||
+ strcmp(tdcontactptr->pass, contactptr->pass) ||
+ strcmp(tdcontactptr->host, contactptr->host) ||
+ strcmp(tdcontactptr->port, contactptr->port) ||
+ strcmp(tdcontactptr->headers, contactptr->headers) ||
+ strcmp(tdcontactptr->expires, contactptr->expires) ||
+ strcmp(tdcontactptr->q, contactptr->q) ||
+ strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
+ strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
+ (tdcontactptr->params.lr != contactptr->params.lr)
+ ) {
+ ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
+ res = AST_TEST_FAIL;
+ break;
+ }
+
+ contactptr = AST_LIST_NEXT(contactptr,list);
+ }
+ }
+
+ }
+
+ return res;
+}
+
void sip_request_parser_register_tests(void)
{
AST_TEST_REGISTER(get_calleridname_test);
AST_TEST_REGISTER(sip_parse_uri_test);
AST_TEST_REGISTER(get_in_brackets_test);
AST_TEST_REGISTER(get_name_and_number_test);
+ AST_TEST_REGISTER(sip_parse_uri_fully_test);
+ AST_TEST_REGISTER(parse_name_andor_addr_test);
+ AST_TEST_REGISTER(parse_contact_header_test);
}
void sip_request_parser_unregister_tests(void)
{
@@ -658,4 +1515,7 @@
AST_TEST_UNREGISTER(get_calleridname_test);
AST_TEST_UNREGISTER(get_in_brackets_test);
AST_TEST_UNREGISTER(get_name_and_number_test);
-}
+ AST_TEST_UNREGISTER(sip_parse_uri_fully_test);
+ AST_TEST_UNREGISTER(parse_name_andor_addr_test);
+ AST_TEST_UNREGISTER(parse_contact_header_test);
+}
Modified: team/rmudgett/call_waiting/funcs/func_srv.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/funcs/func_srv.c?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/funcs/func_srv.c (original)
+++ team/rmudgett/call_waiting/funcs/func_srv.c Fri Apr 9 14:10:03 2010
@@ -31,6 +31,8 @@
#include "asterisk/srv.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
+#include "asterisk/datastore.h"
+#include "asterisk/channel.h"
/*** DOCUMENTATION
<function name="SRVQUERY" language="en_US">
Modified: team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in?view=diff&rev=256605&r1=256604&r2=256605
==============================================================================
--- team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in (original)
+++ team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in Fri Apr 9 14:10:03 2010
@@ -679,6 +679,10 @@
library. */
#undef HAVE_PRI_CALL_REROUTING
+/* Define to 1 if you have the ISDN PRI call completion supplementary service
+ library. */
+#undef HAVE_PRI_CCSS
+
/* Define to 1 if you have the ISDN PRI set_inbanddisconnect library. */
#undef HAVE_PRI_INBANDDISCONNECT
@@ -1288,9 +1292,6 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if the C compiler supports function prototypes. */
-#undef PROTOTYPES
-
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
@@ -1309,11 +1310,6 @@
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
-
-/* Define to 1 if the `setvbuf' function takes the buffering type as its
- second argument and the buffer pointer as the third, as on System V before
- release 3. */
-#undef SETVBUF_REVERSED
/* The size of `char *', as computed by sizeof. */
#undef SIZEOF_CHAR_P
@@ -1344,20 +1340,30 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
-/* Define to 1 if on AIX 3.
- System headers sometimes define this.
- We just want to avoid a redefinition error message. */
+/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#undef _FILE_OFFSET_BITS
-
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
#undef _LARGEFILE_SOURCE
@@ -1374,20 +1380,6 @@
[... 34 lines stripped ...]
More information about the asterisk-commits
mailing list