Fixed bugs with the parsing (re: allowable chars): (1) Parameters in URI and header should have different spec. URI should use paramchar spec while header should use token spec (thanks Jeroen van Bemmel) (2) The same rule applies when escaping the parameters during printing process (3) While we're on it, also fixed the tel-URI parser to automatically unescape the parameter values.

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@606 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h
index 54dd52d..fe78839 100644
--- a/pjsip/include/pjsip/sip_parser.h
+++ b/pjsip/include/pjsip/sip_parser.h
@@ -314,7 +314,7 @@
     pjsip_TOKEN_SPEC,		/**< Token. */
     pjsip_HEX_SPEC,	        /**< Hexadecimal digits. */
     pjsip_PARAM_CHAR_SPEC,      /**< For scanning pname (or pvalue when it's 
-				     not quoted.) */
+				     not quoted.) in URI */
     pjsip_PARAM_CHAR_SPEC_ESC,	/**< Variant without the escape ('%') char */
     pjsip_HDR_CHAR_SPEC,	/**< Chars in hname/havalue in URL. */
     pjsip_HDR_CHAR_SPEC_ESC,	/**< Variant without the escape ('%') char */
@@ -356,11 +356,17 @@
     PJSIP_PARSE_REMOVE_QUOTE = 1,
 };
 
+/* Parse parameter in header (matching the character as token) */
 void pjsip_parse_param_imp(  pj_scanner *scanner, pj_pool_t *pool,
 			     pj_str_t *pname, pj_str_t *pvalue,
 			     unsigned opt);
+/* Parse parameter in URL (matching the character as paramchar) */
+void pjsip_parse_uri_param_imp(  pj_scanner *scanner, pj_pool_t *pool,
+				 pj_str_t *pname, pj_str_t *pvalue,
+				 unsigned opt);
 void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, 
-			 const pj_str_t *pname, const pj_str_t *pvalue, int sepchar);
+			     const pj_str_t *pname, const pj_str_t *pvalue, 
+			     int sepchar);
 void pjsip_parse_end_hdr_imp ( pj_scanner *scanner );
 
 PJ_END_DECL
diff --git a/pjsip/src/pjsip-simple/evsub_msg.c b/pjsip/src/pjsip-simple/evsub_msg.c
index 7fd44d3..cf73527 100644
--- a/pjsip/src/pjsip-simple/evsub_msg.c
+++ b/pjsip/src/pjsip-simple/evsub_msg.c
@@ -70,8 +70,8 @@
     copy_advance_pair(p, ";id=", 4, hdr->id_param);
     
     printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
-				   &pjsip_PARAM_CHAR_SPEC, 
-				   &pjsip_PARAM_CHAR_SPEC, ';');
+				   &pjsip_TOKEN_SPEC, 
+				   &pjsip_TOKEN_SPEC, ';');
     if (printed < 0)
 	return printed;
 
@@ -180,8 +180,8 @@
     }
     
     printed = pjsip_param_print_on( &hdr->other_param, p, endbuf-p, 
-				    &pjsip_PARAM_CHAR_SPEC,
-				    &pjsip_PARAM_CHAR_SPEC,
+				    &pjsip_TOKEN_SPEC,
+				    &pjsip_TOKEN_SPEC,
 				    ';');
     if (printed < 0)
 	return printed;
diff --git a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c
index 84c41cc..011e255 100644
--- a/pjsip/src/pjsip/sip_auth_msg.c
+++ b/pjsip/src/pjsip/sip_auth_msg.c
@@ -81,8 +81,8 @@
     copy_advance_pair(buf, ", nc=", 5, cred->nc);
     
     printed = pjsip_param_print_on(&cred->other_param, buf, endbuf-buf, 
-				   &pjsip_PARAM_CHAR_SPEC, 
-				   &pjsip_PARAM_CHAR_SPEC, ',');
+				   &pjsip_TOKEN_SPEC, 
+				   &pjsip_TOKEN_SPEC, ',');
     if (printed < 0)
 	return -1;
     buf += printed;
@@ -235,8 +235,8 @@
     copy_advance_pair_quote_cond(buf, ",qop=", 5, chal->qop, '"', '"');
     
     printed = pjsip_param_print_on(&chal->other_param, buf, endbuf-buf, 
-				   &pjsip_PARAM_CHAR_SPEC, 
-				   &pjsip_PARAM_CHAR_SPEC, ',');
+				   &pjsip_TOKEN_SPEC, 
+				   &pjsip_TOKEN_SPEC, ',');
     if (printed < 0)
 	return -1;
     buf += printed;
diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index d6a3333..72808a5 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -1039,8 +1039,8 @@
 	}
 
 	printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,
-				       &pjsip_PARAM_CHAR_SPEC,
-				       &pjsip_PARAM_CHAR_SPEC, ';');
+				       &pjsip_TOKEN_SPEC, &pjsip_TOKEN_SPEC, 
+				       ';');
 	if (printed < 0)
 	    return printed;
 	buf += printed;
@@ -1282,8 +1282,8 @@
     copy_advance_pair(buf, ";tag=", 5, hdr->tag);
 
     printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, 
-				   &pjsip_PARAM_CHAR_SPEC,
-				   &pjsip_PARAM_CHAR_SPEC, ';');
+				   &pjsip_TOKEN_SPEC,
+				   &pjsip_TOKEN_SPEC, ';');
     if (printed < 0)
 	return -1;
     buf += printed;
@@ -1453,8 +1453,8 @@
     buf += printed;
 
     printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, 
-				   &pjsip_PARAM_CHAR_SPEC, 
-				   &pjsip_PARAM_CHAR_SPEC, ';');
+				   &pjsip_TOKEN_SPEC, 
+				   &pjsip_TOKEN_SPEC, ';');
     if (printed < 0)
 	return -1;
     buf += printed;
@@ -1672,8 +1672,8 @@
     copy_advance_pair(buf, ";branch=", 8, hdr->branch_param);
     
     printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, 
-				   &pjsip_PARAM_CHAR_SPEC,
-				   &pjsip_PARAM_CHAR_SPEC, ';');
+				   &pjsip_TOKEN_SPEC,
+				   &pjsip_TOKEN_SPEC, ';');
     if (printed < 0)
 	return -1;
     buf += printed;
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index b0fbc0d..df9f02f 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -40,8 +40,8 @@
 #define ESCAPED		    "%"
 #define USER_UNRESERVED	    "&=+$,;?/"
 #define PASS		    "&=+$,"
-#define TOKEN		    "-.!%*_=`'~+"   /* '+' is because of app/pidf+xml
-					     * in Content-Type! */
+#define TOKEN		    "-.!%*_`'~+"   /* '=' was removed for parsing 
+					    * param */
 #define HOST		    "_-."
 #define HEX_DIGIT	    "abcdefABCDEF"
 #define PARAM_CHAR	    "[]/:&+$" UNRESERVED ESCAPED
@@ -138,6 +138,10 @@
 				     pj_pool_t *pool,
 				     pj_str_t *pname, 
 				     pj_str_t *pvalue);
+static void	    int_parse_uri_param( pj_scanner *scanner, 
+					 pj_pool_t *pool,
+					 pj_str_t *pname, 
+					 pj_str_t *pvalue);
 static void	    int_parse_hparam( pj_scanner *scanner,
 				      pj_pool_t *pool,
 				      pj_str_t *hname,
@@ -324,6 +328,9 @@
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
     pj_cis_add_str( &pjsip_TOKEN_SPEC, TOKEN);
 
+    /* TOKEN must not have '%' */
+    pj_assert(pj_cis_match(&pjsip_TOKEN_SPEC, '%')==0);
+
     status = pj_cis_dup(&pjsip_HOST_SPEC, &pjsip_ALNUM_SPEC);
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
     pj_cis_add_str( &pjsip_HOST_SPEC, HOST);
@@ -1038,14 +1045,15 @@
     return msg;
 }
 
+
 /* Parse parameter (pname ["=" pvalue]). */
-void pjsip_parse_param_imp(  pj_scanner *scanner, pj_pool_t *pool,
+static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
 			     pj_str_t *pname, pj_str_t *pvalue,
+			     const pj_cis_t *spec, const pj_cis_t *esc_spec,
 			     unsigned option)
 {
     /* pname */
-    parser_get_and_unescape(scanner, pool, &pjsip_PARAM_CHAR_SPEC,
-			    &pjsip_PARAM_CHAR_SPEC_ESC, pname);
+    parser_get_and_unescape(scanner, pool, spec, esc_spec, pname);
 
     /* init pvalue */
     pvalue->ptr = NULL;
@@ -1062,15 +1070,34 @@
 		    pvalue->ptr++;
 		    pvalue->slen -= 2;
 		}
-	    } else if(pj_cis_match(&pjsip_PARAM_CHAR_SPEC, *scanner->curptr)) {
-		parser_get_and_unescape(scanner, pool, &pjsip_PARAM_CHAR_SPEC, 
-					&pjsip_PARAM_CHAR_SPEC_ESC, pvalue);
+	    } else if(pj_cis_match(spec, *scanner->curptr)) {
+		parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue);
 	    }
 	}
     }
 }
 
-/* Parse parameter (";" pname ["=" pvalue]). */
+/* Parse parameter (pname ["=" pvalue]) using token. */
+void pjsip_parse_param_imp(  pj_scanner *scanner, pj_pool_t *pool,
+			     pj_str_t *pname, pj_str_t *pvalue,
+			     unsigned option)
+{
+    parse_param_imp(scanner, pool, pname, pvalue, &pjsip_TOKEN_SPEC,
+		    &pjsip_TOKEN_SPEC, option);
+}
+
+
+/* Parse parameter (pname ["=" pvalue]) using paramchar. */
+void pjsip_parse_uri_param_imp(pj_scanner *scanner, pj_pool_t *pool,
+			       pj_str_t *pname, pj_str_t *pvalue,
+			       unsigned option)
+{
+    parse_param_imp(scanner, pool, pname, pvalue, &pjsip_PARAM_CHAR_SPEC,
+		    &pjsip_PARAM_CHAR_SPEC_ESC, option);
+}
+
+
+/* Parse parameter (";" pname ["=" pvalue]) in header. */
 static void int_parse_param( pj_scanner *scanner, pj_pool_t *pool,
 			     pj_str_t *pname, pj_str_t *pvalue)
 {
@@ -1082,6 +1109,19 @@
 			  PJSIP_PARSE_REMOVE_QUOTE);
 }
 
+/* Parse parameter (";" pname ["=" pvalue]) in URI. */
+static void int_parse_uri_param( pj_scanner *scanner, pj_pool_t *pool,
+				 pj_str_t *pname, pj_str_t *pvalue)
+{
+    /* Get ';' character */
+    pj_scan_get_char(scanner);
+
+    /* Get pname and optionally pvalue */
+    pjsip_parse_uri_param_imp(scanner, pool, pname, pvalue, 
+			      PJSIP_PARSE_REMOVE_QUOTE);
+}
+
+
 /* Parse header parameter. */
 static void int_parse_hparam( pj_scanner *scanner, pj_pool_t *pool,
 			      pj_str_t *hname, pj_str_t *hvalue )
@@ -1297,7 +1337,7 @@
       while (*scanner->curptr == ';' ) {
 	pj_str_t pname, pvalue;
 
-	int_parse_param( scanner, pool, &pname, &pvalue);
+	int_parse_uri_param( scanner, pool, &pname, &pvalue);
 
 	if (!parser_stricmp(pname, pjsip_USER_STR) && pvalue.slen) {
 	    url->user_param = pvalue;
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
index 34d28b1..04141b8 100644
--- a/pjsip/src/pjsip/sip_tel_uri.c
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -55,7 +55,9 @@
 static pj_cis_t pjsip_TEL_VISUAL_SEP_SPEC;
 static pj_cis_t pjsip_TEL_PNAME_SPEC;
 static pj_cis_t pjsip_TEL_PVALUE_SPEC;
+static pj_cis_t pjsip_TEL_PVALUE_SPEC_ESC;
 static pj_cis_t pjsip_TEL_PARSING_PVALUE_SPEC;
+static pj_cis_t pjsip_TEL_PARSING_PVALUE_SPEC_ESC;
 
 static pj_str_t pjsip_ISUB_STR = { "isub", 4 };
 static pj_str_t pjsip_EXT_STR = { "ext", 3 };
@@ -152,11 +154,18 @@
     pj_cis_add_num(&pjsip_TEL_PVALUE_SPEC);
     pj_cis_add_str(&pjsip_TEL_PVALUE_SPEC, PARAM_CHAR);
 
+    status = pj_cis_dup(&pjsip_TEL_PVALUE_SPEC_ESC, &pjsip_TEL_PVALUE_SPEC);
+    pj_cis_del_str(&pjsip_TEL_PVALUE_SPEC_ESC, "%");
+
     status = pj_cis_dup(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_URIC_SPEC);
     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
     pj_cis_add_cis(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_PVALUE_SPEC);
     pj_cis_add_str(&pjsip_TEL_PARSING_PVALUE_SPEC, "=");
 
+    status = pj_cis_dup(&pjsip_TEL_PARSING_PVALUE_SPEC_ESC, 
+			&pjsip_TEL_PARSING_PVALUE_SPEC);
+    pj_cis_del_str(&pjsip_TEL_PVALUE_SPEC_ESC, "%");
+
     status = pjsip_register_uri_parser("tel", &tel_uri_parse);
     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
@@ -393,7 +402,17 @@
 
 	    if (*scanner->curptr == '=') {
 		pj_scan_get_char(scanner);
-		pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC, &pvalue);
+
+#		if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
+		    pj_scan_get_unescape( scanner, 
+					  &pjsip_TEL_PARSING_PVALUE_SPEC_ESC,
+					  &pvalue);
+#		else
+		    pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC, 
+				&pvalue);
+		    *token = pj_str_unescape(pool, &pvalue);
+#		endif
+
 	    } else {
 		pvalue.slen = 0;
 		pvalue.ptr = NULL;