Fixed several bugs in PJSUA-API:
- in some condition, when outgoing call fails, call count
  incorrectly decremented to -1
- introduce account priority in pjsua_acc_config, and
  improve the account searching for incoming calls
- pjsua will hangup call after sending transfer/REFER request.



git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@737 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 0a106f4..82e22ab 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1020,10 +1020,25 @@
 
 
 /**
+ * Default account priority.
+ */
+#ifndef PJSUA_DEFAULT_ACC_PRIORITY
+#   define PJSUA_DEFAULT_ACC_PRIORITY	0
+#endif
+
+
+/**
  * Account configuration.
  */
 typedef struct pjsua_acc_config
 {
+    /**
+     * Account priority, which is used to control the order of matching
+     * incoming/outgoing requests. The higher the number means the higher
+     * the priority is, and the account will be matched first.
+     */
+    int		    priority;
+
     /** 
      * The full SIP URL for the account. The value can take name address or 
      * URL format, and will look something like "sip:account@serviceprovider".
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 10e7663..ca9a51d 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -189,6 +189,7 @@
     unsigned		 acc_cnt;	     /**< Number of accounts.	*/
     pjsua_acc_id	 default_acc;	     /**< Default account ID	*/
     pjsua_acc		 acc[PJSUA_MAX_ACC]; /**< Account array.	*/
+    pjsua_acc_id	 acc_ids[PJSUA_MAX_ACC]; /**< Acc sorted by prio*/
 
     /* Calls: */
     pjsua_config	 ua_cfg;		/**< UA config.		*/
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index d545bdf..5578e7f 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -229,6 +229,16 @@
     /* Mark account as valid */
     pjsua_var.acc[acc_id].valid = PJ_TRUE;
 
+    /* Insert account ID into account ID array, sorted by priority */
+    for (i=0; i<pjsua_var.acc_cnt; ++i) {
+	if ( pjsua_var.acc[pjsua_var.acc_ids[i]].cfg.priority <
+	     pjsua_var.acc[acc_id].cfg.priority)
+	{
+	    break;
+	}
+    }
+    pj_array_insert(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
+		    pjsua_var.acc_cnt, i, &acc_id);
 
     return PJ_SUCCESS;
 }
@@ -321,6 +331,9 @@
     
     pjsua_acc_config_default(&cfg);
 
+    /* Lower the priority of local account */
+    --cfg.priority;
+
     /* Build URI for the account */
     pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE,
 		     "<sip:%.*s:%d;transport=%s>", 
@@ -340,6 +353,8 @@
  */
 PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
 {
+    unsigned i;
+
     PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
 		     PJ_EINVAL);
     PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
@@ -356,6 +371,17 @@
     /* Invalidate */
     pjsua_var.acc[acc_id].valid = PJ_FALSE;
 
+    /* Remove from array */
+    for (i=0; i<pjsua_var.acc_cnt; ++i) {
+	if (pjsua_var.acc_ids[i] == acc_id)
+	    break;
+    }
+    if (i != pjsua_var.acc_cnt) {
+	pj_array_erase(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
+		       pjsua_var.acc_cnt, i);
+	--pjsua_var.acc_cnt;
+    }
+
     PJ_TODO(may_need_to_scan_calls);
 
     PJSUA_UNLOCK();
@@ -709,7 +735,7 @@
     pj_str_t tmp;
     pjsip_uri *uri;
     pjsip_sip_uri *sip_uri;
-    unsigned acc_id;
+    unsigned i;
 
     PJSUA_LOCK();
 
@@ -719,74 +745,59 @@
 
     uri = pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen, 0);
     if (!uri) {
-	acc_id = pjsua_var.default_acc;
-	goto on_return;
+	PJSUA_UNLOCK();
+	return pjsua_var.default_acc;
     }
 
     if (!PJSIP_URI_SCHEME_IS_SIP(uri) && 
 	!PJSIP_URI_SCHEME_IS_SIPS(uri)) 
     {
 	/* Return the first account with proxy */
-	for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) {
-	    if (!pjsua_var.acc[acc_id].valid)
+	for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	    if (!pjsua_var.acc[i].valid)
 		continue;
-	    if (!pj_list_empty(&pjsua_var.acc[acc_id].route_set))
+	    if (!pj_list_empty(&pjsua_var.acc[i].route_set))
 		break;
 	}
 
-	if (acc_id != PJ_ARRAY_SIZE(pjsua_var.acc)) {
+	if (i != PJ_ARRAY_SIZE(pjsua_var.acc)) {
 	    /* Found rather matching account */
-	    goto on_return;
+	    PJSUA_UNLOCK();
+	    return 0;
 	}
 
 	/* Not found, use default account */
-	acc_id = pjsua_var.default_acc;
-	goto on_return;
+	PJSUA_UNLOCK();
+	return pjsua_var.default_acc;
     }
 
     sip_uri = pjsip_uri_get_uri(uri);
 
-    /* See if default acc match */
-    if (pjsua_var.default_acc != PJSUA_INVALID_ID &&
-	pj_stricmp(&pjsua_var.acc[pjsua_var.default_acc].srv_domain, &sip_uri->host)==0 &&
-	pjsua_var.acc[pjsua_var.default_acc].srv_port == sip_uri->port) 
-    {
-	acc_id = pjsua_var.default_acc;
-    } else {
-	acc_id = PJ_ARRAY_SIZE(pjsua_var.acc);
-    }
-
     /* Find matching domain AND port */
-    if (acc_id == PJ_ARRAY_SIZE(pjsua_var.acc)) {
-	for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) {
-	    if (!pjsua_var.acc[acc_id].valid)
-		continue;
-	    if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0 &&
-		pjsua_var.acc[acc_id].srv_port == sip_uri->port)
-		break;
+    for (i=0; i<pjsua_var.acc_cnt; ++i) {
+	unsigned acc_id = pjsua_var.acc_ids[i];
+	if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0 &&
+	    pjsua_var.acc[acc_id].srv_port == sip_uri->port)
+	{
+	    PJSUA_UNLOCK();
+	    return acc_id;
 	}
     }
 
     /* If no match, try to match the domain part only */
-    if (acc_id == PJ_ARRAY_SIZE(pjsua_var.acc)) {
-	/* Just use default account */
-	for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) {
-	    if (!pjsua_var.acc[acc_id].valid)
-		continue;
-	    if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0)
-		break;
+    for (i=0; i<pjsua_var.acc_cnt; ++i) {
+	unsigned acc_id = pjsua_var.acc_ids[i];
+	if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0)
+	{
+	    PJSUA_UNLOCK();
+	    return acc_id;
 	}
     }
 
-    if (acc_id == PJ_ARRAY_SIZE(pjsua_var.acc)) {
-	/* Just use default account */
-	acc_id = pjsua_var.default_acc;
-    }
 
-on_return:
+    /* Still no match, just use default account */
     PJSUA_UNLOCK();
-
-    return acc_id;
+    return pjsua_var.default_acc;
 }
 
 
@@ -798,7 +809,7 @@
 {
     pjsip_uri *uri;
     pjsip_sip_uri *sip_uri;
-    unsigned acc_id;
+    unsigned i;
 
     uri = rdata->msg_info.to->uri;
 
@@ -815,8 +826,8 @@
     sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
 
     /* Find account which has matching username and domain. */
-    for (acc_id=0; acc_id < pjsua_var.acc_cnt; ++acc_id) {
-
+    for (i=0; i < pjsua_var.acc_cnt; ++i) {
+	unsigned acc_id = pjsua_var.acc_ids[i];
 	pjsua_acc *acc = &pjsua_var.acc[acc_id];
 
 	if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&
@@ -828,9 +839,9 @@
 	}
     }
 
-    /* No matching, try match domain part only. */
-    for (acc_id=0; acc_id < pjsua_var.acc_cnt; ++acc_id) {
-
+    /* No matching account, try match domain part only. */
+    for (i=0; i < pjsua_var.acc_cnt; ++i) {
+	unsigned acc_id = pjsua_var.acc_ids[i];
 	pjsua_acc *acc = &pjsua_var.acc[acc_id];
 
 	if (pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) {
@@ -840,6 +851,18 @@
 	}
     }
 
+    /* No matching account, try match user part only. */
+    for (i=0; i < pjsua_var.acc_cnt; ++i) {
+	unsigned acc_id = pjsua_var.acc_ids[i];
+	pjsua_acc *acc = &pjsua_var.acc[acc_id];
+
+	if (pj_stricmp(&acc->user_part, &sip_uri->user)==0) {
+	    /* Match ! */
+	    PJSUA_UNLOCK();
+	    return acc_id;
+	}
+    }
+
     /* Still no match, use default account */
     PJSUA_UNLOCK();
     return pjsua_var.default_acc;
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 35eee94..bb2ccd1 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -237,6 +237,9 @@
 
     call = &pjsua_var.calls[call_id];
 
+    PJ_LOG(4,(THIS_FILE, "Making call with acc #%d to %.*s", acc_id,
+	      (int)dest_uri->slen, dest_uri->ptr));
+
     /* Mark call start time. */
     pj_gettimeofday(&call->start_time);
 
@@ -316,6 +319,9 @@
 
     pjsua_process_msg_data( tdata, msg_data);
 
+    /* Must increment call counter now */
+    ++pjsua_var.call_cnt;
+
     /* Send initial INVITE: */
 
     status = pjsip_inv_send_msg(inv, tdata);
@@ -333,8 +339,6 @@
 
     /* Done. */
 
-    ++pjsua_var.call_cnt;
-
     if (p_call_id)
 	*p_call_id = call_id;
 
@@ -462,7 +466,7 @@
      * call. We need the account to find which contact URI to put for
      * the call.
      */
-    acc_id = pjsua_acc_find_for_incoming(rdata);
+    acc_id = call->acc_id = pjsua_acc_find_for_incoming(rdata);
 
     /* Get suitable Contact header */
     status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,