[asterisk-commits] mmichelson: branch group/CCSS r243220 - in /team/group/CCSS: ./ channels/ inc...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jan 26 11:21:53 CST 2010


Author: mmichelson
Date: Tue Jan 26 11:21:47 2010
New Revision: 243220

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=243220
Log:
Resolve conflict in chan_sip and reset automerge.


Added:
    team/group/CCSS/tests/test_utils.c
      - copied unchanged from r243200, trunk/tests/test_utils.c
Modified:
    team/group/CCSS/   (props changed)
    team/group/CCSS/channels/chan_sip.c
    team/group/CCSS/include/asterisk/utils.h
    team/group/CCSS/main/test.c
    team/group/CCSS/main/utils.c

Propchange: team/group/CCSS/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/group/CCSS/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Jan 26 11:21:47 2010
@@ -1,1 +1,1 @@
-/trunk:1-243164
+/trunk:1-243215

Modified: team/group/CCSS/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/channels/chan_sip.c?view=diff&rev=243220&r1=243219&r2=243220
==============================================================================
--- team/group/CCSS/channels/chan_sip.c (original)
+++ team/group/CCSS/channels/chan_sip.c Tue Jan 26 11:21:47 2010
@@ -240,6 +240,7 @@
 #include "asterisk/utils.h"
 #include "asterisk/file.h"
 #include "asterisk/astobj.h"
+#include "asterisk/test.h"
 /*
    Uncomment the define below,  if you are having refcount related memory leaks.
    With this uncommented, this module will generate a file, /tmp/refs, which contains
@@ -1225,6 +1226,12 @@
 static struct sip_settings sip_cfg;		/*!< SIP configuration data.
 					\note in the future we could have multiple of these (per domain, per device group etc) */
 
+/*!< use this macro when ast_uri_decode is dependent on pedantic checking to be on. */
+#define SIP_PEDANTIC_DECODE(str)	\
+	if (sip_cfg.pedanticsipchecking && !ast_strlen_zero(str)) {	\
+		ast_uri_decode(str);	\
+	}	\
+
 static int global_match_auth_username;		/*!< Match auth username if available instead of From: Default off. */
 
 static int global_relaxdtmf;		/*!< Relax DTMF */
@@ -3222,7 +3229,7 @@
 static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
 static int set_address_from_contact(struct sip_pvt *pvt);
 static void check_via(struct sip_pvt *p, struct sip_request *req);
-static char *get_calleridname(const char *input, char *output, size_t outputsize);
+static const char *get_calleridname(const char *input, char *output, size_t outputsize);
 static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
 static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
 static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
@@ -14813,47 +14820,33 @@
 	enum check_auth_result res = AUTH_NOT_FOUND;
 	struct sip_peer *peer;
 	char tmp[256];
-	char *name, *c;
-	char *domain;
+	char *name = NULL, *c, *domain = NULL;
 	char *uri2 = ast_strdupa(uri);
 
 	terminate_uri(uri2);
 
 	ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp));
-	if (sip_cfg.pedanticsipchecking)
-		ast_uri_decode(tmp);
 
 	c = get_in_brackets(tmp);
 	c = remove_uri_parameters(c);
 
-	if (!strncasecmp(c, "sip:", 4)) {
-		name = c + 4;
-	} else if (!strncasecmp(c, "sips:", 5)) {
-		name = c + 5;
-	} else {
-		name = c;
+	if (parse_uri(c, "sip:,sips:", &name, NULL, &domain, NULL, NULL, NULL)) {
 		ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr));
-	}
+		return -1;
+	}
+
+	SIP_PEDANTIC_DECODE(name);
+	SIP_PEDANTIC_DECODE(domain);
 
 	/*! \todo XXX here too we interpret a missing @domain as a name-only
 	 * URI, whereas the RFC says this is a domain-only uri.
 	 */
-	/* Strip off the domain name */
-	if ((c = strchr(name, '@'))) {
-		*c++ = '\0';
-		domain = c;
-		if ((c = strchr(domain, ':')))	/* Remove :port */
-			*c = '\0';
-		if (!AST_LIST_EMPTY(&domain_list)) {
-			if (!check_sip_domain(domain, NULL, 0)) {
-				transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
-				return AUTH_UNKNOWN_DOMAIN;
-			}
-		}
-	}
-	c = strchr(name, ';');	/* Remove any Username parameters */
-	if (c)
-		*c = '\0';
+	if (!ast_strlen_zero(domain) && !AST_LIST_EMPTY(&domain_list)) {
+		if (!check_sip_domain(domain, NULL, 0)) {
+			transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+			return AUTH_UNKNOWN_DOMAIN;
+		}
+	}
 
 	ast_string_field_set(p, exten, name);
 	build_contact(p);
@@ -15330,10 +15323,9 @@
 */
 static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id)
 {
-	char tmp[256] = "", *uri, *a;
+	char tmp[256] = "", *uri, *domain;
 	char tmpf[256] = "", *from = NULL;
 	struct sip_request *req;
-	char *colon;
 	char *decoded_uri;
 
 	req = oreq;
@@ -15344,19 +15336,17 @@
 	if (req->rlPart2)
 		ast_copy_string(tmp, REQ_OFFSET_TO_STR(req, rlPart2), sizeof(tmp));
 	
-	if (sip_cfg.pedanticsipchecking)
-		ast_uri_decode(tmp);
-
-	uri = ast_strdupa(get_in_brackets(tmp));
-	
-	if (!strncasecmp(uri, "sip:", 4)) {
-		uri += 4;
-	} else if (!strncasecmp(uri, "sips:", 5)) {
-		uri += 5;
-	} else {
-		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", uri);
+	uri = get_in_brackets(tmp);
+
+	if (parse_uri(uri, "sip:,sips:", &uri, NULL, &domain, NULL, NULL, NULL)) {
+		ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
 		return -1;
 	}
+
+	SIP_PEDANTIC_DECODE(domain);
+	SIP_PEDANTIC_DECODE(uri);
+
+	ast_string_field_set(p, domain, domain);
 
 	/* Now find the From: caller ID and name */
 	/* XXX Why is this done in get_destination? Isn't it already done?
@@ -15364,46 +15354,17 @@
         */
 	ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
 	if (!ast_strlen_zero(tmpf)) {
-		if (sip_cfg.pedanticsipchecking)
-			ast_uri_decode(tmpf);
 		from = get_in_brackets(tmpf);
-	}
-	
-	if (!ast_strlen_zero(from)) {
-		if (!strncasecmp(from, "sip:", 4)) {
-			from += 4;
-		} else if (!strncasecmp(from, "sips:", 5)) {
-			from += 5;
-		} else {
-			ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", from);
+		if (parse_uri(from, "sip:,sips:", &from, NULL, &domain, NULL, NULL, NULL)) {
+			ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from);
 			return -1;
 		}
-		if ((a = strchr(from, '@')))
-			*a++ = '\0';
-		else
-			a = from;	/* just a domain */
-		from = strsep(&from, ";");	/* Remove userinfo options */
-		a = strsep(&a, ";");		/* Remove URI options */
-		ast_string_field_set(p, fromdomain, a);
-	}
-
-	/* Skip any options and find the domain */
-
-	/* Get the target domain */
-	if ((a = strchr(uri, '@'))) {
-		*a++ = '\0';
-	} else {	/* No username part */
-		a = uri;
-		uri = "s";	/* Set extension to "s" */
-	}
-	colon = strchr(a, ':'); /* Remove :port */
-	if (colon)
-		*colon = '\0';
-
-	uri = strsep(&uri, ";");	/* Remove userinfo options */
-	a = strsep(&a, ";");		/* Remove URI options */
-
-	ast_string_field_set(p, domain, a);
+
+		SIP_PEDANTIC_DECODE(from);
+		SIP_PEDANTIC_DECODE(domain);
+
+		ast_string_field_set(p, fromdomain, domain);
+	}
 
 	if (!AST_LIST_EMPTY(&domain_list)) {
 		char domain_context[AST_MAX_EXTENSION];
@@ -15592,9 +15553,6 @@
 	}
 	h_refer_to = ast_strdupa(p_refer_to);
 	refer_to = get_in_brackets(h_refer_to);
-	if (sip_cfg.pedanticsipchecking)
-		ast_uri_decode(refer_to);
-
 	if (!strncasecmp(refer_to, "sip:", 4)) {
 		refer_to += 4;			/* Skip sip: */
 	} else if (!strncasecmp(refer_to, "sips:", 5)) {
@@ -15619,8 +15577,6 @@
 	if (!ast_strlen_zero(p_referred_by)) {
 		char *lessthan;
 		h_referred_by = ast_strdupa(p_referred_by);
-		if (sip_cfg.pedanticsipchecking)
-			ast_uri_decode(h_referred_by);
 
 		/* Store referrer's caller ID name */
 		ast_copy_string(referdata->referred_by_name, h_referred_by, sizeof(referdata->referred_by_name));
@@ -15629,6 +15585,7 @@
 		}
 
 		referred_by_uri = get_in_brackets(h_referred_by);
+
 		if (!strncasecmp(referred_by_uri, "sip:", 4)) {
 			referred_by_uri += 4;		/* Skip sip: */
 		} else if (!strncasecmp(referred_by_uri, "sips:", 5)) {
@@ -15646,7 +15603,6 @@
 		/* This is an attended transfer */
 		referdata->attendedtransfer = 1;
 		ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
-		ast_uri_decode(referdata->replaces_callid);
 		if ((ptr = strchr(referdata->replaces_callid, ';'))) 	/* Find options */ {
 			*ptr++ = '\0';
 		}
@@ -15664,6 +15620,7 @@
 				*to = '\0';
 			if ((to = strchr(ptr, ';')))
 				*to = '\0';
+			ast_uri_decode(ptr);
 			ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag));
 		}
 		
@@ -15673,6 +15630,7 @@
 				*to = '\0';
 			if ((to = strchr(ptr, ';')))
 				*to = '\0';
+			ast_uri_decode(ptr);
 			ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag));
 		}
 		
@@ -15693,19 +15651,26 @@
 		if ((ptr = strchr(domain, ':')))	/* Remove :port */
 			*ptr = '\0';
 		
+		SIP_PEDANTIC_DECODE(domain);
+		SIP_PEDANTIC_DECODE(urioption);
+
 		/* Save the domain for the dial plan */
 		ast_copy_string(referdata->refer_to_domain, domain, sizeof(referdata->refer_to_domain));
-		if (urioption)
+		if (urioption) {
 			ast_copy_string(referdata->refer_to_urioption, urioption, sizeof(referdata->refer_to_urioption));
+		}
 	}
 
 	if ((ptr = strchr(refer_to, ';'))) 	/* Remove options */
 		*ptr = '\0';
+
+	SIP_PEDANTIC_DECODE(refer_to);
 	ast_copy_string(referdata->refer_to, refer_to, sizeof(referdata->refer_to));
 	
 	if (referred_by_uri) {
 		if ((ptr = strchr(referred_by_uri, ';'))) 	/* Remove options */
 			*ptr = '\0';
+		SIP_PEDANTIC_DECODE(referred_by_uri);
 		ast_copy_string(referdata->referred_by, referred_by_uri, sizeof(referdata->referred_by));
 	} else {
 		referdata->referred_by[0] = '\0';
@@ -15757,26 +15722,18 @@
 	ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp));
 	c = get_in_brackets(tmp);
 
-	if (sip_cfg.pedanticsipchecking)
-		ast_uri_decode(c);
-
-	if (!strncasecmp(c, "sip:", 4)) {
-		c += 4;
-	} else if (!strncasecmp(c, "sips:", 5)) {
-		c += 5;
-	} else {
+	if (parse_uri(c, "sip:,sips:", &c, NULL, &a, NULL, NULL, NULL)) {
 		ast_log(LOG_WARNING, "Huh?  Not a SIP header in Also: transfer (%s)?\n", c);
 		return -1;
 	}
-
-	if ((a = strchr(c, ';'))) 	/* Remove arguments */
-		*a = '\0';
 	
-	if ((a = strchr(c, '@'))) {	/* Separate Domain */
-		*a++ = '\0';
+	SIP_PEDANTIC_DECODE(c);
+	SIP_PEDANTIC_DECODE(a);
+
+	if (!ast_strlen_zero(a)) {
 		ast_copy_string(referdata->refer_to_domain, a, sizeof(referdata->refer_to_domain));
 	}
-	
+
 	if (sip_debug_test_pvt(p))
 		ast_verbose("Looking for %s in %s\n", c, p->context);
 
@@ -15903,48 +15860,185 @@
 	}
 }
 
-/*! \brief  Get caller id name from SIP headers */
-static char *get_calleridname(const char *input, char *output, size_t outputsize)
-{
-	const char *end = strchr(input, '<');	/* first_bracket */
-	const char *tmp = strchr(input, '"');	/* first quote */
-	int bytes = 0;
-	int maxbytes = outputsize - 1;
-
-	if (!end || end == input)	/* we require a part in brackets */
-		return NULL;
-
-	end--; /* move just before "<" */
-
-	if (tmp && tmp <= end) {
-		/* The quote (tmp) precedes the bracket (end+1).
-		 * Find the matching quote and return the content.
-		 */
-		end = strchr(tmp+1, '"');
-		if (!end)
-			return NULL;
-		bytes = (int) (end - tmp);
-		/* protect the output buffer */
-		if (bytes > maxbytes)
-			bytes = maxbytes;
-		ast_copy_string(output, tmp + 1, bytes);
-	} else {
-		/* No quoted string, or it is inside brackets. */
-		/* clear the empty characters in the begining*/
-		input = ast_skip_blanks(input);
-		/* clear the empty characters in the end */
-		while(*end && *end < 33 && end > input)
-			end--;
-		if (end >= input) {
-			bytes = (int) (end - input) + 2;
-			/* protect the output buffer */
-			if (bytes > maxbytes)
-				bytes = maxbytes;
-			ast_copy_string(output, input, bytes);
-		} else
-			return NULL;
-	}
-	return output;
+/*! \brief  Get caller id name from SIP headers, copy into output buffer
+ *
+ *  \retval input string pointer placed after display-name field if possible
+ */
+static const char *get_calleridname(const char *input, char *output, size_t outputsize)
+{
+	/* From RFC3261:
+	 * 
+	 * From           =  ( "From" / "f" ) HCOLON from-spec
+	 * from-spec      =  ( name-addr / addr-spec ) *( SEMI from-param )
+	 * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
+	 * display-name   =  *(token LWS)/ quoted-string
+	 * token          =  1*(alphanum / "-" / "." / "!" / "%" / "*"
+	 *                     / "_" / "+" / "`" / "'" / "~" )
+	 * quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
+	 * qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
+	 *                     / UTF8-NONASCII
+	 * quoted-pair    =  "\" (%x00-09 / %x0B-0C / %x0E-7F)
+	 *
+	 * HCOLON         = *WSP ":" SWS
+	 * SWS            = [LWS]
+	 * LWS            = *[*WSP CRLF] 1*WSP
+	 * WSP            = (SP / HTAB)
+	 *
+	 * Deviations from it:
+	 * - following CRLF's in LWS is not done (here at least)
+	 * - ascii NUL is never legal as it terminates the C-string
+	 * - utf8-nonascii is not checked for validity
+	 */
+	char *orig_output = output;
+	const char *orig_input = input;
+
+	/* clear any empty characters in the beginning */
+	input = ast_skip_blanks(input);
+
+	/* no data at all or no storage room? */
+	if (!input || *input == '<' || !outputsize || !output) {
+		return orig_input;
+	}
+
+	/* make sure the output buffer is initilized */
+	*orig_output = '\0';
+
+	/* make room for '\0' at the end of the output buffer */
+	outputsize--;
+
+	/* quoted-string rules */
+	if (input[0] == '"') {
+		input++; /* skip the first " */
+
+		for (;((outputsize > 0) && *input); input++) {
+			if (*input == '"') {  /* end of quoted-string */
+				break;
+			} else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
+				input++;
+				if (!*input || (unsigned char)*input > 0x7f || *input == 0xa || *input == 0xd) {
+					continue;  /* not a valid quoted-pair, so skip it */
+				}
+			} else if (((*input != 0x9) && ((unsigned char) *input < 0x20)) ||
+			            (*input == 0x7f)) {
+				continue; /* skip this invalid character. */
+			}
+
+			*output++ = *input;
+			outputsize--;
+		}
+
+		/* if this is successful, input should be at the ending quote */
+		if (!input || *input != '"') {
+			ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
+			*orig_output = '\0';
+			return orig_input;
+		}
+
+		/* make sure input is past the last quote */
+		input++;
+
+		/* terminate outbuf */
+		*output = '\0';
+	} else {  /* either an addr-spec or tokenLWS-combo */
+		for (;((outputsize > 0) && *input); input++) {
+			/* token or WSP (without LWS) */
+			if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
+				|| (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
+				|| *input == '!' || *input == '%' || *input == '*' || *input == '_'
+				|| *input == '+' || *input == '`' || *input == '\'' || *input == '~'
+				|| *input == 0x9 || *input == ' ') {
+				*output++ = *input;
+				outputsize -= 1;
+			} else if (*input == '<') {   /* end of tokenLWS-combo */
+				/* we could assert that the previous char is LWS, but we don't care */
+				break;
+			} else if (*input == ':') {
+				/* This invalid character which indicates this is addr-spec rather than display-name. */
+				*orig_output = '\0';
+				return orig_input;
+			} else {         /* else, invalid character we can skip. */
+				continue;    /* skip this character */
+			}
+		}
+
+		/* set NULL while trimming trailing whitespace */
+		do {
+			*output-- = '\0';
+		} while (*output == 0x9 || *output == ' '); /* we won't go past orig_output as first was a non-space */
+	}
+
+	return input;
+}
+
+AST_TEST_DEFINE(get_calleridname_test)
+{
+	int res = AST_TEST_PASS;
+	const char *in1 = "\" quoted-text internal \\\" quote \"<stuff>";
+	const char *in2 = " token text with no quotes <stuff>";
+	const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
+	const char *noendquote = " \"quoted-text no end <stuff>";
+	const char *addrspec = " \"sip:blah at blah <stuff>";
+	const char *after_dname;
+	char dname[40];
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "sip_get_calleridname_test";
+		info->category = "channels/chan_sip/";
+		info->summary = "decodes callerid name from sip header";
+		info->description = "Decodes display-name field of sip header.  Checks for valid output and expected failure cases.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	/* quoted-text with backslash escaped quote */
+	after_dname = get_calleridname(in1, dname, sizeof(dname));
+	ast_test_status_update(&args->status_update, "display-name1: %s\nafter: %s\n", dname, after_dname);
+	if (strcmp(dname, " quoted-text internal \" quote ")) {
+		ast_test_status_update(&args->status_update, "display-name1 test failed\n");
+		ast_str_append(&args->ast_test_error_str, 0, "quoted-text with internal backslash decode failed. \n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* token text */
+	after_dname = get_calleridname(in2, dname, sizeof(dname));
+	ast_test_status_update(&args->status_update, "display-name2: %s\nafter: %s\n", dname, after_dname);
+	if (strcmp(dname, "token text with no quotes")) {
+		ast_test_status_update(&args->status_update, "display-name2 test failed\n");
+		ast_str_append(&args->ast_test_error_str, 0, "token text with decode failed. \n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* quoted-text buffer overflow */
+	after_dname = get_calleridname(overflow1, dname, sizeof(dname));
+	ast_test_status_update(&args->status_update, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
+	if (*dname != '\0' && after_dname != overflow1) {
+		ast_test_status_update(&args->status_update, "overflow display-name1 test failed\n");
+		ast_str_append(&args->ast_test_error_str, 0, "quoted-text buffer overflow check failed. \n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* quoted-text buffer with no terminating end quote */
+	after_dname = get_calleridname(noendquote, dname, sizeof(dname));
+	ast_test_status_update(&args->status_update, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
+	if (*dname != '\0' && after_dname != noendquote) {
+		ast_test_status_update(&args->status_update, "no end quote for quoted-text display-name failed\n");
+		ast_str_append(&args->ast_test_error_str, 0, "quoted-text buffer check no terminating end quote failed. \n");
+		res = AST_TEST_FAIL;
+	}
+
+	/* addr-spec rather than display-name. */
+	after_dname = get_calleridname(addrspec, dname, sizeof(dname));
+	ast_test_status_update(&args->status_update, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
+	if (*dname != '\0' && after_dname != addrspec) {
+		ast_test_status_update(&args->status_update, "detection of addr-spec failed\n");
+		ast_str_append(&args->ast_test_error_str, 0, "detection of addr-spec failed. \n");
+		res = AST_TEST_FAIL;
+	}
+
+
+	return res;
 }
 
 
@@ -16121,26 +16215,29 @@
 					      int sipmethod, const char *uri, enum xmittype reliable,
 					      struct sockaddr_in *sin, struct sip_peer **authpeer)
 {
-	char from[256];
+	char from[256] = { 0, };
 	char *dummy;	/* dummy return value for parse_uri */
 	char *domain;	/* dummy return value for parse_uri */
 	char *of;
-	enum check_auth_result res;
+	enum check_auth_result res = AUTH_DONT_KNOW;
 	char calleridname[50];
 	char *uri2 = ast_strdupa(uri);
 
 	terminate_uri(uri2);	/* trim extra stuff */
 
 	ast_copy_string(from, get_header(req, "From"), sizeof(from));
-	if (sip_cfg.pedanticsipchecking)
-		ast_uri_decode(from);
 	/* XXX here tries to map the username for invite things */
 	memset(calleridname, 0, sizeof(calleridname));
-	get_calleridname(from, calleridname, sizeof(calleridname));
+
+	/* strip the display-name portion off the beginning of the FROM header. */
+	if (!(of = (char *) get_calleridname(from, calleridname, sizeof(calleridname)))) {
+		ast_log(LOG_ERROR, "FROM header can not be parsed \n");
+		return res;
+	}
+
 	if (calleridname[0])
 		ast_string_field_set(p, cid_name, calleridname);
 
-	of = get_in_brackets(from);
 	if (ast_strlen_zero(p->exten)) {
 		char *t = uri2;
 		if (!strncasecmp(t, "sip:", 4))
@@ -16151,9 +16248,13 @@
 		t = strchr(p->exten, '@');
 		if (t)
 			*t = '\0';
+
 		if (ast_strlen_zero(p->our_contact))
 			build_contact(p);
 	}
+
+	of = get_in_brackets(of);
+
 	/* save the URI part of the From header */
 	ast_string_field_set(p, from, of);
 
@@ -16161,6 +16262,9 @@
 	if (parse_uri(of, "sip:,sips:", &of, &dummy, &domain, &dummy, &dummy, NULL)) {
 		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
 	}
+
+	SIP_PEDANTIC_DECODE(of);
+	SIP_PEDANTIC_DECODE(domain);
 
 	if (ast_strlen_zero(of)) {
 		/* XXX note: the original code considered a missing @host
@@ -22267,7 +22371,6 @@
 			ast_debug(3, "INVITE part of call transfer. Replaces [%s]\n", p_replaces);
 		/* Create a buffer we can manipulate */
 		replace_id = ast_strdupa(p_replaces);
-		ast_uri_decode(replace_id);
 
 		if (!p->refer && !sip_refer_allocate(p)) {
 			transmit_response_reliable(p, "500 Server Internal Error", req);
@@ -22298,6 +22401,10 @@
 				fromtag = strsep(&fromtag, "&"); /* trim what ? */
 			}
 		}
+
+		ast_uri_decode(fromtag);
+		ast_uri_decode(totag);
+		ast_uri_decode(replace_id);
 
 		if (sipdebug)
 			ast_debug(4, "Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n",
@@ -28925,6 +29032,18 @@
 	AST_CLI_DEFINE(sip_show_tcp, "List TCP Connections")
 };
 
+/*! \brief SIP test registration */
+static void sip_register_tests(void)
+{
+	AST_TEST_REGISTER(get_calleridname_test);
+}
+
+/*! \brief SIP test registration */
+static void sip_unregister_tests(void)
+{
+	AST_TEST_UNREGISTER(get_calleridname_test);
+}
+
 /*! \brief PBX load module - initialization */
 static int load_module(void)
 {
@@ -29034,6 +29153,9 @@
 		"lastms", RQ_INTEGER4, 11,
 		SENTINEL);
 
+
+	sip_register_tests();
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -29160,6 +29282,8 @@
 	ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
 	ast_cc_agent_unregister(&sip_cc_agent_callbacks);
 
+	sip_unregister_tests();
+
 	return 0;
 }
 

Modified: team/group/CCSS/include/asterisk/utils.h
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/include/asterisk/utils.h?view=diff&rev=243220&r1=243219&r2=243220
==============================================================================
--- team/group/CCSS/include/asterisk/utils.h (original)
+++ team/group/CCSS/include/asterisk/utils.h Tue Jan 26 11:21:47 2010
@@ -248,22 +248,25 @@
  */
 int ast_base64decode(unsigned char *dst, const char *src, int max);
 
-/*!  \brief Turn text string to URI-encoded %XX version 
-
-\note 	At this point, we're converting from ISO-8859-x (8-bit), not UTF8
-	as in the SIP protocol spec 
-	If doreserved == 1 we will convert reserved characters also.
-	RFC 2396, section 2.4
-	outbuf needs to have more memory allocated than the instring
-	to have room for the expansion. Every char that is converted
-	is replaced by three ASCII characters.
-	\param string	String to be converted
-	\param outbuf	Resulting encoded string
-	\param buflen	Size of output buffer
-	\param doreserved	Convert reserved characters
-*/
-
-char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved);
+/*! \brief Turn text string to URI-encoded %XX version 
+ *
+ * \note 
+ *  At this point, this function is encoding agnostic; it does not
+ *  check whether it is fed legal UTF-8. We escape control
+ *  characters (\x00-\x1F\x7F), '%', and all characters above 0x7F.
+ *  If do_special_char == 1 we will convert all characters except alnum
+ *  and the mark set.
+ *  Outbuf needs to have more memory allocated than the instring
+ *  to have room for the expansion. Every char that is converted
+ *  is replaced by three ASCII characters.
+ *
+ *  \param string	String to be converted
+ *  \param outbuf	Resulting encoded string
+ *  \param buflen	Size of output buffer
+ *  \param do_special_char	Convert all non alphanum characters execept
+ *         those in the mark set as defined by rfc 3261 section 25.1
+ */
+char *ast_uri_encode(const char *string, char *outbuf, int buflen, int do_special_char);
 
 /*!	\brief Decode URI, URN, URL (overwrite string)
 	\param s	String to be decoded 
@@ -755,4 +758,8 @@
  */
 int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2);
 
+/*!
+ * \brief Registers util api unit tests
+ */
+void ast_utils_register_tests(void);
 #endif /* _ASTERISK_UTILS_H */

Modified: team/group/CCSS/main/test.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/main/test.c?view=diff&rev=243220&r1=243219&r2=243220
==============================================================================
--- team/group/CCSS/main/test.c (original)
+++ team/group/CCSS/main/test.c Tue Jan 26 11:21:47 2010
@@ -833,9 +833,6 @@
 #ifdef TEST_FRAMEWORK
 	/* Register cli commands */
 	ast_cli_register_multiple(test_cli, ARRAY_LEN(test_cli));
-
-	/* in the future this function could be used to register functions not
-	 * defined within a module */
 #endif
 
 	return 0;

Modified: team/group/CCSS/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/main/utils.c?view=diff&rev=243220&r1=243219&r2=243220
==============================================================================
--- team/group/CCSS/main/utils.c (original)
+++ team/group/CCSS/main/utils.c Tue Jan 26 11:21:47 2010
@@ -368,41 +368,44 @@
 	b2a[(int)'/'] = 63;
 }
 
-/*! \brief  ast_uri_encode: Turn text string to URI-encoded %XX version
-\note 	At this point, we're converting from ISO-8859-x (8-bit), not UTF8
-	as in the SIP protocol spec 
-	If doreserved == 1 we will convert reserved characters also.
-	RFC 2396, section 2.4
-	outbuf needs to have more memory allocated than the instring
-	to have room for the expansion. Every char that is converted
-	is replaced by three ASCII characters.
-
-	Note: The doreserved option is needed for replaces header in
-	SIP transfers.
-*/
-char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved) 
-{
-	char *reserved = ";/?:@&=+$,# ";	/* Reserved chars */
-
- 	const char *ptr  = string;	/* Start with the string */
+/*! \brief Turn text string to URI-encoded %XX version 
+ *
+ * \note 
+ *  At this point, this function is encoding agnostic; it does not
+ *  check whether it is fed legal UTF-8. We escape control
+ *  characters (\x00-\x1F\x7F), '%', and all characters above 0x7F.
+ *  If do_special_char == 1 we will convert all characters except alnum
+ *  and mark.
+ *  Outbuf needs to have more memory allocated than the instring
+ *  to have room for the expansion. Every char that is converted
+ *  is replaced by three ASCII characters.
+ */
+char *ast_uri_encode(const char *string, char *outbuf, int buflen, int do_special_char)
+{
+	const char *ptr  = string;	/* Start with the string */
 	char *out = NULL;
 	char *buf = NULL;
-
+	const char *mark = "-_.!~*'()"; /* no encode set, RFC 2396 section 2.3, RFC 3261 sec 25 */
 	ast_copy_string(outbuf, string, buflen);
 
-	/* If there's no characters to convert, just go through and don't do anything */
 	while (*ptr) {
-		if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
+		if ((const signed char) *ptr < 32 || *ptr == 0x7f || *ptr == '%' ||
+				(do_special_char &&
+				!(*ptr >= '0' && *ptr <= '9') &&      /* num */
+				!(*ptr >= 'A' && *ptr <= 'Z') &&      /* ALPHA */
+				!(*ptr >= 'a' && *ptr <= 'z') &&      /* alpha */
+				!strchr(mark, *ptr))) {               /* mark set */
+
 			/* Oops, we need to start working here */
 			if (!buf) {
 				buf = outbuf;
 				out = buf + (ptr - string) ;	/* Set output ptr */
 			}
-			out += sprintf(out, "%%%02x", (unsigned char) *ptr);
+			out += sprintf(out, "%%%02X", (unsigned char) *ptr);
 		} else if (buf) {
 			*out = *ptr;	/* Continue copying the string */
 			out++;
-		} 
+		}
 		ptr++;
 	}
 	if (buf)




More information about the asterisk-commits mailing list