Index: pjproject/trunk/pjsip/src/pjsua/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 230)
+++ pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 236)
@@ -46,4 +46,6 @@
 void pjsua_default(void)
 {
+    unsigned i;
+
 
     /* Normally need another thread for console application, because main 
@@ -54,10 +56,8 @@
 
     /* Default transport settings: */
-
     pjsua.sip_port = 5060;
 
 
     /* Default logging settings: */
-
     pjsua.log_level = 5;
     pjsua.app_log_level = 4;
@@ -65,31 +65,27 @@
 		      PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE;
 
+
     /* Default: do not use STUN: */
-
     pjsua.stun_port1 = pjsua.stun_port2 = 0;
 
-    /* Default URIs: */
-
-    pjsua.local_uri = pj_str(PJSUA_LOCAL_URI);
-
-    /* Default registration timeout: */
-
-    pjsua.reg_timeout = 55;
-
-    /* Default maximum conference ports: */
-
-    pjsua.max_ports = 8;
-
-    /* Init route set list: */
-
-    pj_list_init(&pjsua.route_set);
-
-    /* Init invite session list: */
-
-    pj_list_init(&pjsua.inv_list);
+    /* Init accounts: */
+    pjsua.acc_cnt = 1;
+    for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) {
+	pjsua.acc[i].index = i;
+	pjsua.acc[i].local_uri = pj_str(PJSUA_LOCAL_URI);
+	pjsua.acc[i].reg_timeout = 55;
+	pj_list_init(&pjsua.acc[i].route_set);
+	pj_list_init(&pjsua.acc[i].pres_srv_list);
+    }
+
+    /* Init call array: */
+    for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i)
+	pjsua.calls[i].index = i;
+
+    /* Default max nb of calls. */
+    pjsua.max_calls = 4;
 
     /* Init server presence subscription list: */
     
-    pj_list_init(&pjsua.pres_srv_list);
 
 }
@@ -111,6 +107,5 @@
     if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {
 
-	return pjsua_inv_on_incoming(rdata);
-
+	return pjsua_call_on_incoming(rdata);
     }
 
@@ -146,5 +141,5 @@
 	RTP_START_PORT = 4000,
 	RTP_RANDOM_START = 2,
-	RTP_RETRY = 20 
+	RTP_RETRY = 100
     };
     enum {
@@ -241,14 +236,17 @@
 		pj_memcpy(&mapped_addr[i], &addr, sizeof(addr));
 
-	    if (sip)
-		mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port);
-	    mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);
-	    mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1));
+	    if (sip) {
+		mapped_addr[SIP_SOCK].sin_port = 
+		    pj_htons((pj_uint16_t)pjsua.sip_port);
+	    }
+	    mapped_addr[RTP_SOCK].sin_port=pj_htons((pj_uint16_t)rtp_port);
+	    mapped_addr[RTCP_SOCK].sin_port=pj_htons((pj_uint16_t)(rtp_port+1));
 	    break;
+
 	} else {
-	    status = pj_stun_get_mapped_addr( &pjsua.cp.factory, 3, sock,
-					      &pjsua.stun_srv1, pjsua.stun_port1,
-					      &pjsua.stun_srv2, pjsua.stun_port2,
-					      mapped_addr);
+	    status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 3, sock,
+					   &pjsua.stun_srv1, pjsua.stun_port1,
+					   &pjsua.stun_srv2, pjsua.stun_port2,
+					   mapped_addr);
 	    if (status != PJ_SUCCESS) {
 		pjsua_perror(THIS_FILE, "STUN error", status);
@@ -256,14 +254,21 @@
 	    }
 
-	    if (pj_ntohs(mapped_addr[2].sin_port) == pj_ntohs(mapped_addr[1].sin_port)+1)
+	    if (pj_ntohs(mapped_addr[2].sin_port) == 
+		pj_ntohs(mapped_addr[1].sin_port)+1)
+	    {
 		break;
-
-	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;
-	    pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
+	    }
+
+	    pj_sock_close(sock[RTP_SOCK]); 
+	    sock[RTP_SOCK] = PJ_INVALID_SOCKET;
+
+	    pj_sock_close(sock[RTCP_SOCK]); 
+	    sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
 	}
     }
 
     if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) {
-	PJ_LOG(1,(THIS_FILE, "Unable to find appropriate RTP/RTCP ports combination"));
+	PJ_LOG(1,(THIS_FILE, 
+		  "Unable to find appropriate RTP/RTCP ports combination"));
 	goto on_error;
     }
@@ -271,5 +276,7 @@
     if (sip) {
 	pjsua.sip_sock = sock[SIP_SOCK];
-	pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
+	pj_memcpy(&pjsua.sip_sock_name, 
+		  &mapped_addr[SIP_SOCK], 
+		  sizeof(pj_sockaddr_in));
     } else {
 	pj_sock_close(sock[0]);
@@ -392,27 +399,10 @@
     /* Initialize invite session module: */
 
-    {
-	
-	/* Initialize invite session callback. */
-	pjsip_inv_callback inv_cb;
-
-	pj_memset(&inv_cb, 0, sizeof(inv_cb));
-	inv_cb.on_state_changed = &pjsua_inv_on_state_changed;
-	inv_cb.on_new_session = &pjsua_inv_on_new_session;
-	inv_cb.on_media_update = &pjsua_inv_on_media_update;
-	inv_cb.on_rx_offer = &pjsua_inv_on_rx_offer;
-	inv_cb.on_tsx_state_changed = &pjsua_inv_on_tsx_state_changed;
-
-
-	/* Initialize invite session module: */
-	status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
-	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Invite usage initialization error", 
-			 status);
-	    goto on_error;
-	}
-
-    }
-
+    status = pjsua_call_init();
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Invite usage initialization error", 
+		     status);
+	goto on_error;
+    }
 
     /* Done */
@@ -521,5 +511,6 @@
     /* Init conference bridge. */
 
-    status = pjmedia_conf_create(pjsua.pool, pjsua.max_ports, 
+    status = pjmedia_conf_create(pjsua.pool, 
+				 pjsua.max_calls+PJSUA_CONF_MORE_PORTS, 
 				 8000, 160, 16, &pjsua.mconf);
     if (status != PJ_SUCCESS) {
@@ -548,4 +539,65 @@
 
 
+/*
+ * Find account for incoming request.
+ */
+int pjsua_find_account_for_incoming(pjsip_rx_data *rdata)
+{
+    pjsip_uri *uri;
+    pjsip_sip_uri *sip_uri;
+    int acc_index;
+
+    uri = rdata->msg_info.to->uri;
+
+    /* Just return account #0 if To URI is not SIP: */
+    if (!PJSIP_URI_SCHEME_IS_SIP(uri) && 
+	!PJSIP_URI_SCHEME_IS_SIPS(uri)) 
+    {
+	return 0;
+    }
+
+
+    sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
+
+    /* Find account which has matching username and domain. */
+    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) {
+
+	pjsua_acc *acc = &pjsua.acc[acc_index];
+
+	if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&
+	    pj_stricmp(&acc->host_part, &sip_uri->host)==0) 
+	{
+	    /* Match ! */
+	    return acc_index;
+	}
+    }
+
+    /* No matching, try match domain part only. */
+    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) {
+
+	pjsua_acc *acc = &pjsua.acc[acc_index];
+
+	if (pj_stricmp(&acc->host_part, &sip_uri->host)==0) {
+	    /* Match ! */
+	    return acc_index;
+	}
+    }
+
+    /* Still no match, just return account #0 */
+    return 0;
+}
+
+
+/*
+ * Find account for outgoing request.
+ */
+int pjsua_find_account_for_outgoing(const pj_str_t *url)
+{
+    PJ_UNUSED_ARG(url);
+
+    /* Just use account #0 */
+    return 0;
+}
+
 
 /*
@@ -589,9 +641,16 @@
 
     /* Init sockets (STUN etc): */
-    for (i=0; i<PJ_ARRAY_SIZE(pjsua.med_sock_info); ++i) {
-	status = init_sockets(i==0, &pjsua.med_sock_info[i]);
+    for (i=0; i<(int)pjsua.max_calls; ++i) {
+	status = init_sockets(i==0, &pjsua.calls[i].skinfo);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "init_sockets() has returned error", 
 			 status);
+	    --i;
+	    if (i >= 0)
+		pj_sock_close(pjsua.sip_sock);
+	    while (i >= 0) {
+		pj_sock_close(pjsua.calls[i].skinfo.rtp_sock);
+		pj_sock_close(pjsua.calls[i].skinfo.rtcp_sock);
+	    }
 	    return status;
 	}
@@ -624,22 +683,13 @@
 
     /* Initialize Contact URI, if one is not specified: */
-
-    if (pjsua.contact_uri.slen == 0 && pjsua.local_uri.slen) {
+    for (i=0; i<pjsua.acc_cnt; ++i) {
 
 	pjsip_uri *uri;
 	pjsip_sip_uri *sip_uri;
-	char contact[128];
-	int len;
-
-	/* The local Contact is the username@ip-addr, where
-	 *  - username is taken from the local URI,
-	 *  - ip-addr in UDP transport's address name (which may have been
-	 *    resolved from STUN.
-	 */
-	
+
 	/* Need to parse local_uri to get the elements: */
 
-	uri = pjsip_parse_uri(pjsua.pool, pjsua.local_uri.ptr, 
-			      pjsua.local_uri.slen, 0);
+	uri = pjsip_parse_uri(pjsua.pool, pjsua.acc[i].local_uri.ptr,
+			      pjsua.acc[i].local_uri.slen, 0);
 	if (uri == NULL) {
 	    pjsua_perror(THIS_FILE, "Invalid local URI", 
@@ -648,8 +698,9 @@
 	}
 
-
 	/* Local URI MUST be a SIP or SIPS: */
 
-	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
+	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && 
+	    !PJSIP_URI_SCHEME_IS_SIPS(uri)) 
+	{
 	    pjsua_perror(THIS_FILE, "Invalid local URI", 
 			 PJSIP_EINVALIDSCHEME);
@@ -662,37 +713,52 @@
 	sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
 
-	
-	/* Build temporary contact string. */
-
-	if (sip_uri->user.slen) {
-
-	    /* With the user part. */
-	    len = pj_snprintf(contact, sizeof(contact),
-			      "<sip:%.*s@%.*s:%d>",
-			      (int)sip_uri->user.slen,
-			      sip_uri->user.ptr,
-			      (int)udp_transport->local_name.host.slen,
-			      udp_transport->local_name.host.ptr,
-			      udp_transport->local_name.port);
-	} else {
-
-	    /* Without user part */
-
-	    len = pj_snprintf(contact, sizeof(contact),
-			      "<sip:%.*s:%d>",
-			      (int)udp_transport->local_name.host.slen,
-			      udp_transport->local_name.host.ptr,
-			      udp_transport->local_name.port);
-	}
-
-	if (len < 1 || len >= sizeof(contact)) {
-	    pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG);
-	    return PJSIP_EURITOOLONG;
-	}
-
-	/* Duplicate Contact uri. */
-
-	pj_strdup2(pjsua.pool, &pjsua.contact_uri, contact);
-
+	pjsua.acc[i].user_part = sip_uri->user;
+	pjsua.acc[i].host_part = sip_uri->host;
+
+	if (pjsua.acc[i].contact_uri.slen == 0 && 
+	    pjsua.acc[i].local_uri.slen) 
+	{
+	    char contact[128];
+	    int len;
+
+	    /* The local Contact is the username@ip-addr, where
+	     *  - username is taken from the local URI,
+	     *  - ip-addr in UDP transport's address name (which may have been
+	     *    resolved from STUN.
+	     */
+	    
+	    /* Build temporary contact string. */
+
+	    if (sip_uri->user.slen) {
+
+		/* With the user part. */
+		len = pj_snprintf(contact, sizeof(contact),
+				  "<sip:%.*s@%.*s:%d>",
+				  (int)sip_uri->user.slen,
+				  sip_uri->user.ptr,
+				  (int)udp_transport->local_name.host.slen,
+				  udp_transport->local_name.host.ptr,
+				  udp_transport->local_name.port);
+	    } else {
+
+		/* Without user part */
+
+		len = pj_snprintf(contact, sizeof(contact),
+				  "<sip:%.*s:%d>",
+				  (int)udp_transport->local_name.host.slen,
+				  udp_transport->local_name.host.ptr,
+				  udp_transport->local_name.port);
+	    }
+
+	    if (len < 1 || len >= sizeof(contact)) {
+		pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG);
+		return PJSIP_EURITOOLONG;
+	    }
+
+	    /* Duplicate Contact uri. */
+
+	    pj_strdup2(pjsua.pool, &pjsua.acc[i].contact_uri, contact);
+
+	}
     }
 
@@ -715,5 +781,7 @@
 	}
 
-	pj_list_push_back(&pjsua.route_set, route);
+	for (i=0; i<pjsua.acc_cnt; ++i) {
+	    pj_list_push_front(&pjsua.acc[i].route_set, route);
+	}
     }
 
@@ -737,12 +805,20 @@
 
     /* Create client registration session: */
-
-    status = pjsua_regc_init();
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Perform registration, if required. */
-    if (pjsua.regc) {
-	pjsua_regc_update(1);
+    for (i=0; i<pjsua.acc_cnt; ++i) {
+	status = pjsua_regc_init(i);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Perform registration, if required. */
+	if (pjsua.acc[i].regc) {
+	    pjsua_regc_update(i, 1);
+	}
+    }
+
+
+    /* Find account for outgoing preence subscription */
+    for (i=0; i<pjsua.buddy_cnt; ++i) {
+	pjsua.buddies[i].acc_index = 
+	    pjsua_find_account_for_outgoing(&pjsua.buddies[i].uri);
     }
 
@@ -777,4 +853,17 @@
     /* Signal threads to quit: */
     pjsua.quit_flag = 1;
+
+    /* Terminate all calls. */
+    pjsua_inv_shutdown();
+
+    /* Terminate all presence subscriptions. */
+    pjsua_pres_shutdown();
+
+    /* Unregister, if required: */
+    for (i=0; i<pjsua.acc_cnt; ++i) {
+	if (pjsua.acc[i].regc) {
+	    pjsua_regc_update(i, 0);
+	}
+    }
 
     /* Wait worker threads to quit: */
@@ -789,15 +878,4 @@
 
 
-    /* Terminate all calls. */
-    pjsua_inv_shutdown();
-
-    /* Terminate all presence subscriptions. */
-    pjsua_pres_shutdown();
-
-    /* Unregister, if required: */
-    if (pjsua.regc) {
-	pjsua_regc_update(0);
-    }
-
     /* Wait for some time to allow unregistration to complete: */
     PJ_LOG(4,(THIS_FILE, "Shutting down..."));
