Closed #1139 (Support for tel: URI in PJSUA-LIB):
 - added new PJSUA API: pjsua_verify_url() which can be used for tel: URI
 - modified and tested according to spec
 - added new PJSIP error code, PJSIP_ENOROUTESET, to indicate that route set is needed to send to tel: URI
 - added couple of unit tests (we can't cover the whole tel: URI scenario yet)


git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@3323 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 1fbea78..ead8594 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -919,7 +919,7 @@
 	    break;
 
 	case OPT_ID:   /* id */
-	    if (pjsua_verify_sip_url(pj_optarg) != 0) {
+	    if (pjsua_verify_url(pj_optarg) != 0) {
 		PJ_LOG(1,(THIS_FILE, 
 			  "Error: invalid SIP URL '%s' "
 			  "in local id argument", pj_optarg));
@@ -1037,7 +1037,7 @@
 	    break;
 
 	case OPT_ADD_BUDDY: /* Add to buddy list. */
-	    if (pjsua_verify_sip_url(pj_optarg) != 0) {
+	    if (pjsua_verify_url(pj_optarg) != 0) {
 		PJ_LOG(1,(THIS_FILE, 
 			  "Error: invalid URL '%s' in "
 			  "--add-buddy option", pj_optarg));
@@ -1421,7 +1421,7 @@
     if (pj_optind != argc) {
 	pj_str_t uri_arg;
 
-	if (pjsua_verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) {
+	if (pjsua_verify_url(argv[pj_optind]) != PJ_SUCCESS) {
 	    PJ_LOG(1,(THIS_FILE, "Invalid SIP URI %s", argv[pj_optind]));
 	    return -1;
 	}
@@ -3276,7 +3276,7 @@
     } else {
 	pj_status_t status;
 
-	if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) {
+	if ((status=pjsua_verify_url(buf)) != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Invalid URL", status);
 	    return;
 	}
@@ -3811,8 +3811,8 @@
 		if (!simple_input("Enter buddy's URI:", buf, sizeof(buf)))
 		    break;
 
-		if (pjsua_verify_sip_url(buf) != PJ_SUCCESS) {
-		    printf("Invalid SIP URI '%s'\n", buf);
+		if (pjsua_verify_url(buf) != PJ_SUCCESS) {
+		    printf("Invalid URI '%s'\n", buf);
 		    break;
 		}
 
diff --git a/pjsip-apps/src/samples/simple_pjsua.c b/pjsip-apps/src/samples/simple_pjsua.c
index ab2d017..b958047 100644
--- a/pjsip-apps/src/samples/simple_pjsua.c
+++ b/pjsip-apps/src/samples/simple_pjsua.c
@@ -117,7 +117,7 @@
 
     /* If argument is specified, it's got to be a valid SIP URL */
     if (argc > 1) {
-	status = pjsua_verify_sip_url(argv[1]);
+	status = pjsua_verify_url(argv[1]);
 	if (status != PJ_SUCCESS) error_exit("Invalid URL in argv", status);
     }
 
diff --git a/pjsip-apps/src/symbian_ua/ua.cpp b/pjsip-apps/src/symbian_ua/ua.cpp
index f38d2e6..a59b95a 100644
--- a/pjsip-apps/src/symbian_ua/ua.cpp
+++ b/pjsip-apps/src/symbian_ua/ua.cpp
@@ -733,7 +733,7 @@
 		break;
 	}
 
-	if (pjsua_verify_sip_url(SIP_DST_URI) == PJ_SUCCESS) {
+	if (pjsua_verify_url(SIP_DST_URI) == PJ_SUCCESS) {
 		pj_str_t dst = pj_str(SIP_DST_URI);
 		pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
 				     NULL, &g_call_id);
diff --git a/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp b/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp
index bf3f7a3..b384c20 100644
--- a/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp
+++ b/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp
@@ -482,7 +482,7 @@
 

 int symbian_ua_makecall(const char* dest_url)

 {

-    if (pjsua_verify_sip_url(dest_url) == PJ_SUCCESS) {

+    if (pjsua_verify_url(dest_url) == PJ_SUCCESS) {

 	    pj_str_t dst = pj_str((char*)dest_url);

 	    pjsua_call_make_call(g_acc_id, &dst, 0, NULL,

 				 NULL, &g_call_id);

diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h
index 15f842a..8e075f2 100644
--- a/pjsip/include/pjsip/sip_errno.h
+++ b/pjsip/include/pjsip/sip_errno.h
@@ -96,6 +96,11 @@
  * SIP object is not initialized.
  */
 #define PJSIP_ENOTINITIALIZED	(PJSIP_ERRNO_START_PJSIP + 4)	/* 171004 */
+/**
+ * @hideinitializer
+ * Missing route set (for tel: URI)
+ */
+#define PJSIP_ENOROUTESET	(PJSIP_ERRNO_START_PJSIP + 5)	/* 171005 */
 
 
 /************************************************************
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 3aa03b9..10e1b0f 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1540,16 +1540,32 @@
 
 /**
  * This is a utility function to verify that valid SIP url is given. If the
- * URL is valid, PJ_SUCCESS will be returned.
+ * URL is a valid SIP/SIPS scheme, PJ_SUCCESS will be returned.
  *
  * @param url		The URL, as NULL terminated string.
  *
  * @return		PJ_SUCCESS on success, or the appropriate error code.
+ *
+ * @see pjsua_verify_url()
  */
 PJ_DECL(pj_status_t) pjsua_verify_sip_url(const char *url);
 
 
 /**
+ * This is a utility function to verify that valid URI is given. Unlike
+ * pjsua_verify_sip_url(), this function will return PJ_SUCCESS if tel: URI
+ * is given.
+ *
+ * @param url		The URL, as NULL terminated string.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ *
+ * @see pjsua_verify_sip_url()
+ */
+PJ_DECL(pj_status_t) pjsua_verify_url(const char *url);
+
+
+/**
  * Schedule a timer entry. Note that the timer callback may be executed
  * by different thread, depending on whether worker thread is enabled or
  * not.
diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c
index 0c15206..afef2a1 100644
--- a/pjsip/src/pjsip/sip_errno.c
+++ b/pjsip/src/pjsip/sip_errno.c
@@ -39,6 +39,7 @@
     PJ_BUILD_ERR( PJSIP_ETYPEEXISTS ,	"Object with the same type exists" ),
     PJ_BUILD_ERR( PJSIP_ESHUTDOWN,	"SIP stack shutting down" ),
     PJ_BUILD_ERR( PJSIP_ENOTINITIALIZED,"SIP object is not initialized." ),
+    PJ_BUILD_ERR( PJSIP_ENOROUTESET,	"Missing route set (for tel: URI)" ),
 
     /* Messaging errors */
     PJ_BUILD_ERR( PJSIP_EINVALIDMSG,	"Invalid message/syntax error" ),
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 2b0933a..b57c948 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -835,9 +835,12 @@
 	dest_info->flag = 
 	    pjsip_transport_get_flag_from_type(dest_info->type);
     } else {
+	/* Should have never reached here; app should have configured route
+	 * set when sending to tel: URI
         pj_assert(!"Unsupported URI scheme!");
+	 */
 	PJ_TODO(SUPPORT_REQUEST_ADDR_RESOLUTION_FOR_TEL_URI);
-	return PJSIP_EINVALIDSCHEME;
+	return PJSIP_ENOROUTESET;
     }
 
     /* Handle IPv6 (http://trac.pjsip.org/repos/ticket/861) */
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index abb61b1..fdd37a5 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -119,7 +119,7 @@
     pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
     pjsua_acc *acc = &pjsua_var.acc[acc_id];
     pjsip_name_addr *name_addr;
-    pjsip_sip_uri *sip_uri, *sip_reg_uri;
+    pjsip_sip_uri *sip_reg_uri;
     pj_status_t status;
     unsigned i;
 
@@ -136,20 +136,29 @@
     }
 
     /* Local URI MUST be a SIP or SIPS: */
-
     if (!PJSIP_URI_SCHEME_IS_SIP(name_addr) && 
 	!PJSIP_URI_SCHEME_IS_SIPS(name_addr)) 
     {
-	pjsua_perror(THIS_FILE, "Invalid local URI", 
-		     PJSIP_EINVALIDSCHEME);
-	return PJSIP_EINVALIDSCHEME;
+	acc->display = name_addr->display;
+	acc->user_part = name_addr->display;
+	acc->srv_domain = pj_str("");
+	acc->srv_port = 0;
+    } else {
+	pjsip_sip_uri *sip_uri;
+
+	/* Get the SIP URI object: */
+	sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(name_addr);
+
+	/* Save the user and domain part. These will be used when finding an
+	 * account for incoming requests.
+	 */
+	acc->display = name_addr->display;
+	acc->user_part = sip_uri->user;
+	acc->srv_domain = sip_uri->host;
+	acc->srv_port = 0;
     }
 
 
-    /* Get the SIP URI object: */
-    sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(name_addr);
-
-
     /* Parse registrar URI, if any */
     if (acc_cfg->reg_uri.slen) {
 	pjsip_uri *reg_uri;
@@ -177,14 +186,6 @@
 	sip_reg_uri = NULL;
     }
 
-    /* Save the user and domain part. These will be used when finding an 
-     * account for incoming requests.
-     */
-    acc->display = name_addr->display;
-    acc->user_part = sip_uri->user;
-    acc->srv_domain = sip_uri->host;
-    acc->srv_port = 0;
-
     if (sip_reg_uri) {
 	acc->srv_port = sip_reg_uri->port;
     }
@@ -2160,7 +2161,7 @@
 
 	/* For non-SIP scheme, route set should be configured */
 	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
-	    return PJSIP_EINVALIDREQURI;
+	    return PJSIP_ENOROUTESET;
 
 	sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
     }
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 9fb0a5d..0dcd0f2 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -2404,6 +2404,29 @@
     return pjsua_var.nat_status;
 }
 
+/*
+ * Verify that valid url is given.
+ */
+PJ_DEF(pj_status_t) pjsua_verify_url(const char *c_url)
+{
+    pjsip_uri *p;
+    pj_pool_t *pool;
+    char *url;
+    int len = (c_url ? pj_ansi_strlen(c_url) : 0);
+
+    if (!len) return PJSIP_EINVALIDURI;
+
+    pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
+    if (!pool) return PJ_ENOMEM;
+
+    url = (char*) pj_pool_alloc(pool, len+1);
+    pj_ansi_strcpy(url, c_url);
+
+    p = pjsip_parse_uri(pool, url, len, 0);
+
+    pj_pool_release(pool);
+    return p ? 0 : PJSIP_EINVALIDURI;
+}
 
 /*
  * Verify that valid SIP url is given.
@@ -2415,10 +2438,10 @@
     char *url;
     int len = (c_url ? pj_ansi_strlen(c_url) : 0);
 
-    if (!len) return -1;
+    if (!len) return PJSIP_EINVALIDURI;
 
     pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
-    if (!pool) return -1;
+    if (!pool) return PJ_ENOMEM;
 
     url = (char*) pj_pool_alloc(pool, len+1);
     pj_ansi_strcpy(url, c_url);
@@ -2431,7 +2454,7 @@
     }
 
     pj_pool_release(pool);
-    return p ? 0 : -1;
+    return p ? 0 : PJSIP_EINVALIDURI;
 }
 
 /*
diff --git a/tests/pjsua/scripts-call/400_tel_uri.py b/tests/pjsua/scripts-call/400_tel_uri.py
new file mode 100644
index 0000000..2b64c30
--- /dev/null
+++ b/tests/pjsua/scripts-call/400_tel_uri.py
@@ -0,0 +1,12 @@
+# $Id$
+#
+from inc_cfg import *
+
+# Simple call
+test_param = TestParam(
+		"tel: URI in From",
+		[
+			InstanceParam("callee", "--null-audio --max-calls=1 --id tel:+111"),
+			InstanceParam("caller", "--null-audio --max-calls=1")
+		]
+		)
diff --git a/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py b/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py
new file mode 100644
index 0000000..3725bf7
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py
@@ -0,0 +1,15 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=tel:+12345 --registrar sip:127.0.0.1:$PORT"
+
+req1 = sip.RecvfromTransaction("", 401,
+				include=["REGISTER sip"], 
+				exclude=["Authorization"],
+				resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+				expect="PJSIP_ENOCREDENTIAL"
+			  )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration with tel: URI test",
+			       pjsua, [req1])