[svn-commits] rmudgett: branch rmudgett/mwi r256606 - in /team/rmudgett/mwi: ./ channels/ c...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Apr 9 14:22:34 CDT 2010


Author: rmudgett
Date: Fri Apr  9 14:22:30 2010
New Revision: 256606

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=256606
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/mwi/   (props changed)
    team/rmudgett/mwi/channels/chan_sip.c
    team/rmudgett/mwi/channels/sig_pri.h
    team/rmudgett/mwi/channels/sip/include/reqresp_parser.h
    team/rmudgett/mwi/channels/sip/include/sip.h
    team/rmudgett/mwi/channels/sip/reqresp_parser.c
    team/rmudgett/mwi/configure
    team/rmudgett/mwi/funcs/func_srv.c
    team/rmudgett/mwi/include/asterisk/autoconfig.h.in
    team/rmudgett/mwi/tests/test_gosub.c

Propchange: team/rmudgett/mwi/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/rmudgett/mwi/
------------------------------------------------------------------------------
--- mwi-integrated (original)
+++ mwi-integrated Fri Apr  9 14:22:30 2010
@@ -1,1 +1,1 @@
-/team/group/CCSS:1-256515
+/team/group/CCSS:1-256605

Propchange: team/rmudgett/mwi/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Fri Apr  9 14:22:30 2010
@@ -1,1 +1,1 @@
-/trunk:1-256505
+/trunk:1-256601

Modified: team/rmudgett/mwi/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/channels/chan_sip.c?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/channels/chan_sip.c (original)
+++ team/rmudgett/mwi/channels/chan_sip.c Fri Apr  9 14:22:30 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/mwi/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/channels/sig_pri.h?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/channels/sig_pri.h (original)
+++ team/rmudgett/mwi/channels/sig_pri.h Fri Apr  9 14:22:30 2010
@@ -31,10 +31,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_SUBCMD_MCID_REQ)
 /* BUGBUG the HAVE_PRI_MWI line is to be removed when the mwi branch is merged to trunk and the configure script is updated. */
 #define HAVE_PRI_MWI 1

Modified: team/rmudgett/mwi/channels/sip/include/reqresp_parser.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/channels/sip/include/reqresp_parser.h?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/channels/sip/include/reqresp_parser.h (original)
+++ team/rmudgett/mwi/channels/sip/include/reqresp_parser.h Fri Apr  9 14:22:30 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/mwi/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/channels/sip/include/sip.h?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/channels/sip/include/sip.h (original)
+++ team/rmudgett/mwi/channels/sip/include/sip.h Fri Apr  9 14:22:30 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/mwi/channels/sip/reqresp_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/channels/sip/reqresp_parser.c?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/channels/sip/reqresp_parser.c (original)
+++ team/rmudgett/mwi/channels/sip/reqresp_parser.c Fri Apr  9 14:22:30 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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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, &params, &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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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 = &params,
+		.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/mwi/funcs/func_srv.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/funcs/func_srv.c?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/funcs/func_srv.c (original)
+++ team/rmudgett/mwi/funcs/func_srv.c Fri Apr  9 14:22:30 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/mwi/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/mwi/include/asterisk/autoconfig.h.in?view=diff&rev=256606&r1=256605&r2=256606
==============================================================================
--- team/rmudgett/mwi/include/asterisk/autoconfig.h.in (original)
+++ team/rmudgett/mwi/include/asterisk/autoconfig.h.in Fri Apr  9 14:22:30 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 @@
 
 /* Define to 1 if you need to in order for `stat' and other things to work. */
 #undef _POSIX_SOURCE
-
-/* Enable extensions on Solaris.  */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-
-/* Define like PROTOTYPES; this can be used by system headers. */
-#undef __PROTOTYPES
 

[... 17 lines stripped ...]



More information about the svn-commits mailing list