Index: pjproject/trunk/pjsip/include/pjsip/sip_dialog.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 159)
+++ pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 160)
@@ -50,4 +50,13 @@
 
 /**
+ * Dialog state.
+ */
+enum pjsip_dialog_state
+{
+    PJSIP_DIALOG_STATE_NULL,
+    PJSIP_DIALOG_STATE_ESTABLISHED,
+};
+
+/**
  * This structure describes the dialog structure.
  */
@@ -68,5 +77,5 @@
 
     /* Dialog's session properties. */
-    pj_bool_t		established;/**< Dialog is established?		    */
+    enum pjsip_dialog_state	state;	    /**< Dialog state.			    */
     pjsip_uri	       *target;	    /**< Current target.		    */
     pjsip_dlg_party     local;	    /**< Local party info.		    */
Index: pjproject/trunk/pjsip/include/pjsip/sip_event.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_event.h	(revision 159)
+++ pjproject/trunk/pjsip/include/pjsip/sip_event.h	(revision 160)
@@ -125,5 +125,4 @@
         {
             pjsip_tx_data       *tdata; /**< The transmit data buffer.  */
-            pjsip_transaction   *tsx;   /**< The transaction.           */
 
         } tx_msg;
@@ -140,5 +139,4 @@
         {
             pjsip_rx_data       *rdata; /**< The receive data buffer.   */
-            pjsip_transaction   *tsx;   /**< The transaction.           */
         } rx_msg;
 
@@ -179,8 +177,7 @@
  * Init tx msg event.
  */
-#define PJSIP_EVENT_INIT_TX_MSG(event,ptsx,ptdata)	\
+#define PJSIP_EVENT_INIT_TX_MSG(event,ptdata)	\
         do { \
             (event).type = PJSIP_EVENT_TX_MSG;          \
-            (event).body.tx_msg.tsx = ptsx;		\
             (event).body.tx_msg.tdata = ptdata;		\
         } while (0)
@@ -189,8 +186,7 @@
  * Init rx msg event.
  */
-#define PJSIP_EVENT_INIT_RX_MSG(event,ptsx,prdata)	\
+#define PJSIP_EVENT_INIT_RX_MSG(event,prdata)	\
         do { \
             (event).type = PJSIP_EVENT_RX_MSG;		\
-            (event).body.rx_msg.tsx = ptsx;		\
             (event).body.rx_msg.rdata = prdata;		\
         } while (0)
Index: pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 159)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 160)
@@ -176,5 +176,7 @@
 /**
  * Create, initialize, and register a new transaction as UAS from the
- * specified incoming request in \c rdata.
+ * specified incoming request in \c rdata. After calling this function,
+ * application MUST call #pjsip_tsx_recv_msg() so that transaction
+ * moves from state NULL.
  *
  * @param tsx_user  Module to be registered as transaction user of the new
@@ -190,4 +192,22 @@
 					   pjsip_transaction **p_tsx );
 
+
+/**
+ * Call this function to manually feed a message to the transaction.
+ * For UAS transaction, application MUST call this function after
+ * UAS transaction has been created.
+ *
+ * This function SHOULD only be called to pass initial request message
+ * to UAS transaction. Before this function returns, on_tsx_state()
+ * callback of the transaction user will be called. If response message
+ * is passed to this function, then on_rx_response() will also be called
+ * before on_tsx_state().
+ *
+ * @param tsx	    The transaction.
+ * @param rdata	    The message.
+ */
+PJ_DECL(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx, 
+				  pjsip_rx_data *rdata);
+
 /**
  * Transmit message in tdata with this transaction. It is possible to
Index: pjproject/trunk/pjsip/include/pjsip/sip_types.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 159)
+++ pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 160)
@@ -134,4 +134,8 @@
 typedef struct pjsip_dialog pjsip_dialog;
 
+/**
+ * Dialog state (sip_dialog.h).
+ */
+enum pjsip_dialog_state pjsip_dialog_state;
 
 /**
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 160)
@@ -110,4 +110,19 @@
 
 /*
+ * Set session state.
+ */
+void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
+		   pjsip_event *e)
+{
+    inv->state = state;
+    if (mod_inv.cb.on_state_changed)
+	(*mod_inv.cb.on_state_changed)(inv, e);
+
+    if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
+	pjsip_dlg_dec_session(inv->dlg);
+}
+
+
+/*
  * Send ACK for 2xx response.
  */
@@ -146,8 +161,13 @@
 {
     pjsip_method *method;
+    pjsip_dialog *dlg;
+    pjsip_inv_session *inv;
 
     /* Only wants to receive request from a dialog. */
-    if (pjsip_rdata_get_dlg(rdata) == NULL)
+    dlg = pjsip_rdata_get_dlg(rdata);
+    if (dlg == NULL)
 	return PJ_FALSE;
+
+    inv = dlg->mod_data[mod_inv.mod.id];
 
     /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK. 
@@ -159,8 +179,19 @@
     if (method->id == PJSIP_INVITE_METHOD ||
 	method->id == PJSIP_CANCEL_METHOD ||
-	method->id == PJSIP_ACK_METHOD ||
 	method->id == PJSIP_BYE_METHOD)
     {
 	return PJ_TRUE;
+    }
+
+    /* On receipt ACK request, when state is CONNECTING,
+     * move state to CONFIRMED.
+     */
+    if (method->id == PJSIP_ACK_METHOD && inv &&
+	inv->state == PJSIP_INV_STATE_CONFIRMED)
+    {
+	pjsip_event event;
+
+	PJSIP_EVENT_INIT_RX_MSG(event, rdata);
+	inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
     }
 
@@ -703,5 +734,5 @@
     inv->pool = dlg->pool;
     inv->role = PJSIP_ROLE_UAS;
-    inv->state = PJSIP_INV_STATE_INCOMING;
+    inv->state = PJSIP_INV_STATE_NULL;
     inv->dlg = dlg;
     inv->options = options;
@@ -1067,17 +1098,4 @@
 
 
-void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
-		   pjsip_event *e)
-{
-    inv->state = state;
-    if (mod_inv.cb.on_state_changed)
-	(*mod_inv.cb.on_state_changed)(inv, e);
-
-    if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
-	pjsip_dlg_dec_session(inv->dlg);
-}
-
-
-
 /*
  * Respond to incoming CANCEL request.
@@ -1164,4 +1182,50 @@
     if (inv->state != PJSIP_INV_STATE_DISCONNECTED)
 	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+}
+
+/*
+ * Respond to BYE request.
+ */
+static void inv_handle_bye_response( pjsip_inv_session *inv,
+				     pjsip_transaction *tsx,
+				     pjsip_rx_data *rdata,
+				     pjsip_event *e )
+{
+    pj_status_t status;
+    
+    if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
+	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+	return;
+    }
+
+    /* Handle 401/407 challenge. */
+    if (tsx->status_code == 401 || tsx->status_code == 407) {
+
+	pjsip_tx_data *tdata;
+	
+	status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess, 
+					    rdata,
+					    tsx->last_tx,
+					    &tdata);
+	
+	if (status != PJ_SUCCESS) {
+	    
+	    /* Does not have proper credentials. 
+	     * End the session anyway.
+	     */
+	    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+	    
+	} else {
+	    /* Re-send BYE. */
+	    status = pjsip_inv_send_msg(inv, tdata, NULL );
+	}
+
+    } else {
+
+	/* End the session. */
+
+	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+    }
+
 }
 
@@ -1197,4 +1261,9 @@
 	    case PJSIP_TSX_STATE_TRYING:
 		inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
+		break;
+	    case PJSIP_TSX_STATE_PROCEEDING:
+		inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
+		if (tsx->status_code > 100)
+		    inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
 		break;
 	    default:
@@ -1464,4 +1533,6 @@
 
 	case PJSIP_TSX_STATE_CONFIRMED:
+	    if (tsx->status_code/100 == 2)
+		inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
 	    break;
 
@@ -1496,5 +1567,16 @@
 	inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
 
-    }
+    } else if (tsx->method.id == PJSIP_BYE_METHOD &&
+	       tsx->role == PJSIP_ROLE_UAC &&
+	       tsx->state == PJSIP_TSX_STATE_COMPLETED)
+    {
+
+	/*
+	 * Outgoing BYE
+	 */
+	inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
+
+    }
+
 }
 
@@ -1514,37 +1596,13 @@
 	tsx->state == PJSIP_TSX_STATE_COMPLETED)
     {
+
 	/*
-	 * Outgoing BYE.
+	 * Outgoing BYE
 	 */
-	pj_status_t status;
-	
-	/* Handle 401/407 challenge. */
-	if (tsx->status_code == 401 || tsx->status_code == 407) {
-
-	    pjsip_tx_data *tdata;
-	    
-	    status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess, 
-					        e->body.tsx_state.src.rdata,
-					        tsx->last_tx,
-					        &tdata);
-	    
-	    if (status != PJ_SUCCESS) {
-		
-		/* Does not have proper credentials. 
-		 * End the session anyway.
-		 */
-		inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
-		
-	    } else {
-		/* Re-send BYE. */
-		status = pjsip_inv_send_msg(inv, tdata, NULL );
-	    }
-
-	} else {
-
-	    /* End the session. */
-
+
+	if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+	    inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
+	else
 	    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
-	}
 
     }
Index: pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 160)
@@ -75,4 +75,5 @@
     dlg->ua = ua;
     dlg->endpt = endpt;
+    dlg->state = PJSIP_DIALOG_STATE_NULL;
 
     status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
@@ -375,4 +376,7 @@
     PJ_TODO(DIALOG_APP_TIMER);
 
+    /* Feed the first request to the transaction. */
+    pjsip_tsx_recv_msg(tsx, rdata);
+
     /* Done. */
     *p_dlg = dlg;
@@ -408,4 +412,9 @@
 		     PJSIP_ENOTRESPONSEMSG);
 
+    /* Status code MUST be 1xx (but not 100), or 2xx */
+    status = rdata->msg_info.msg->line.status.code;
+    PJ_ASSERT_RETURN( (status/100==1 && status!=100) ||
+		      (status/100==2), PJ_EBUG);
+
     /* To tag must present in the response. */
     PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
@@ -444,4 +453,13 @@
     /* Initial role is UAC. */
     dlg->role = PJSIP_ROLE_UAC;
+
+    /* Dialog state depends on the response. */
+    status = rdata->msg_info.msg->line.status.code/100;
+    if (status == 1 || status == 2)
+	dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
+    else {
+	pj_assert(!"Invalid status code");
+	dlg->state = PJSIP_DIALOG_STATE_NULL;
+    }
 
     /* Secure? */
@@ -463,5 +481,5 @@
     }
 
-    /* Init client authentication session. */
+    /* Clone client authentication session. */
     status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess, 
 				  &first_dlg->auth_sess);
@@ -850,4 +868,69 @@
 }
 
+/* Add standard headers for certain types of response */
+static void dlg_beautify_response(pjsip_dialog *dlg,
+				  int st_code,
+				  pjsip_tx_data *tdata)
+{
+    pjsip_cseq_hdr *cseq;
+    int st_class;
+    const pjsip_hdr *c_hdr;
+    pjsip_hdr *hdr;
+
+    cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
+    pj_assert(cseq != NULL);
+
+    st_class = st_code / 100;
+
+    /* Contact, Allow, Supported header. */
+    if (pjsip_method_creates_dialog(&cseq->method)) {
+	/* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
+	if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
+	    st_code==485) 
+	{
+	    /* Add contact header only if one is not present. */
+	    if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0) {
+		hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
+		pjsip_msg_add_hdr(tdata->msg, hdr);
+	    }
+	}
+
+	/* Add Allow header in 2xx and 405 response. */
+	if ((st_class==2 || st_code==405) &&
+	    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL) 
+	{
+	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
+					       PJSIP_H_ALLOW, NULL);
+	    if (c_hdr) {
+		hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+		pjsip_msg_add_hdr(tdata->msg, hdr);
+	    }
+	}
+
+	/* Add Supported header in 2xx response. */
+	if (st_class==2 && 
+	    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL)==NULL) 
+	{
+	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
+					       PJSIP_H_SUPPORTED, NULL);
+	    if (c_hdr) {
+		hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+		pjsip_msg_add_hdr(tdata->msg, hdr);
+	    }
+	}
+
+    }
+
+    /* Add To tag in all responses except 100 */
+    if (st_code != 100) {
+	pjsip_to_hdr *to;
+
+	to = PJSIP_MSG_TO_HDR(tdata->msg);
+	pj_assert(to != NULL);
+
+	to->tag = dlg->local.info->tag;
+    }
+}
+
 
 /*
@@ -861,9 +944,10 @@
 {
     pj_status_t status;
-    pjsip_cseq_hdr *cseq;
     pjsip_tx_data *tdata;
-    int st_class;
-
-    /* Create generic response. */
+
+    /* Create generic response.
+     * This will initialize response's Via, To, From, Call-ID, CSeq
+     * and Record-Route headers from the request.
+     */
     status = pjsip_endpt_create_response(dlg->endpt,
 					 rdata, st_code, st_text, &tdata);
@@ -874,88 +958,5 @@
     pj_mutex_lock(dlg->mutex);
 
-    /* Special treatment for 2xx response to request that establishes 
-     * dialog. 
-     *
-     * RFC 3261 Section 12.1.1
-     *
-     * When a UAS responds to a request with a response that establishes 
-     * a dialog (such as a 2xx to INVITE):
-     * - MUST copy all Record-Route header field values from the request 
-     *	 into the response (including the URIs, URI parameters, and any 
-     *	 Record-Route header field parameters, whether they are known or
-     *	 unknown to the UAS) and MUST maintain the order of those values.
-     * - The Contact header field contains an address where the UAS would
-     *	 like to be contacted for subsequent requests in the dialog.
-     *
-     * Also from Table 3, page 119.
-     */
-    cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
-    pj_assert(cseq != NULL);
-
-    st_class = st_code / 100;
-
-    if (cseq->cseq == dlg->remote.first_cseq &&
-	(st_class==1 || st_class==2) && st_code != 100)
-    {
-	pjsip_hdr *rr, *hdr;
-
-	/* Duplicate Record-Route header from the request. */
-	rr = (pjsip_hdr*) rdata->msg_info.record_route;
-	while (rr) {
-	    hdr = pjsip_hdr_clone(tdata->pool, rr);
-	    pjsip_msg_add_hdr(tdata->msg, hdr);
-
-	    rr = rr->next;
-	    if (rr == &rdata->msg_info.msg->hdr)
-		break;
-	    rr = pjsip_msg_find_hdr(rdata->msg_info.msg, 
-				    PJSIP_H_RECORD_ROUTE, rr);
-	}
-    }
-
-    /* Contact header. */
-    if (pjsip_method_creates_dialog(&cseq->method)) {
-	/* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
-	if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
-	    st_code==485) 
-	{
-	    /* Add contact header. */
-	    pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
-	    pjsip_msg_add_hdr(tdata->msg, hdr);
-	}
-
-	/* Add Allow header in 2xx and 405 response. */
-	if (st_class==2 || st_code==405) {
-	    const pjsip_hdr *c_hdr;
-	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
-					       PJSIP_H_ALLOW, NULL);
-	    if (c_hdr) {
-		pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
-		pjsip_msg_add_hdr(tdata->msg, hdr);
-	    }
-	}
-
-	/* Add Supported header in 2xx response. */
-	if (st_class==2) {
-	    const pjsip_hdr *c_hdr;
-	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
-					       PJSIP_H_SUPPORTED, NULL);
-	    if (c_hdr) {
-		pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
-		pjsip_msg_add_hdr(tdata->msg, hdr);
-	    }
-	}
-
-    }
-
-    /* Add To tag in all responses except 100 */
-    if (st_code != 100 && rdata->msg_info.to->tag.slen == 0) {
-	pjsip_to_hdr *to;
-
-	to = PJSIP_MSG_TO_HDR(tdata->msg);
-	pj_assert(to != NULL);
-
-	to->tag = dlg->local.info->tag;
-    }
+    dlg_beautify_response(dlg, st_code, tdata);
 
     /* Unlock the dialog. */
@@ -981,4 +982,7 @@
     PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
 
+    pj_mutex_lock(dlg->mutex);
+
+    /* Replace status code and reason */
     tdata->msg->line.status.code = st_code;
     if (st_text) {
@@ -987,4 +991,15 @@
 	tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
     }
+
+    dlg_beautify_response(dlg, st_code, tdata);
+
+
+    /* Must add reference counter, since tsx_send_msg() will decrement it */
+    pjsip_tx_data_add_ref(tdata);
+
+    /* Force to re-print message. */
+    pjsip_tx_data_invalidate_msg(tdata);
+
+    pj_mutex_unlock(dlg->mutex);
 
     return PJ_SUCCESS;
@@ -1058,5 +1073,5 @@
 {
     pj_status_t status;
-    pjsip_transaction *tsx;
+    pjsip_transaction *tsx = NULL;
     unsigned i;
 
@@ -1065,9 +1080,13 @@
 
     /* Check CSeq */
-    if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq) {
+    if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq &&
+	rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD &&
+	rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) 
+    {
 	/* Invalid CSeq.
 	 * Respond statelessly with 500 (Internal Server Error)
 	 */
 	pj_mutex_unlock(dlg->mutex);
+	pj_assert(pjsip_rdata_get_tsx(rdata) == NULL);
 	pjsip_endpt_respond_stateless(dlg->endpt,
 				      rdata, 500, NULL, NULL, NULL);
@@ -1079,12 +1098,14 @@
 
     /* Create UAS transaction for this request. */
-    status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
-    PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
-
-    /* Put this dialog in the transaction data. */
-    tsx->mod_data[dlg->ua->id] = dlg;
-
-    /* Add transaction count. */
-    ++dlg->tsx_count;
+    if (pjsip_rdata_get_tsx(rdata) == NULL) {
+	status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
+	PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
+
+	/* Put this dialog in the transaction data. */
+	tsx->mod_data[dlg->ua->id] = dlg;
+
+	/* Add transaction count. */
+	++dlg->tsx_count;
+    }
 
     /* Report the request to dialog usages. */
@@ -1101,26 +1122,7 @@
     }
 
-    if (i==dlg->usage_cnt) {
-	pjsip_tx_data *tdata;
-
-	PJ_LOG(4,(dlg->obj_name, 
-		  "%s is unhandled by dialog usages. "
-		  "Dialog will response with 500 (Internal Server Error)",
-		  pjsip_rx_data_get_info(rdata)));
-	status = pjsip_endpt_create_response(dlg->endpt, 
-					     rdata, 
-					     PJSIP_SC_INTERNAL_SERVER_ERROR, 
-					     NULL, &tdata);
-	if (status == PJ_SUCCESS)
-	    status = pjsip_tsx_send_msg(tsx, tdata);
-
-	if (status != PJ_SUCCESS) {
-	    char errmsg[PJSIP_ERR_MSG_SIZE];
-	    pj_strerror(status, errmsg, sizeof(errmsg));
-	    PJ_LOG(4,(dlg->obj_name,"Error sending %s: %s",
-		      pjsip_tx_data_get_info(tdata), errmsg));
-	    pjsip_tsx_terminate(tsx, 500);
-	}
-    }
+    /* Feed the first request to the transaction. */
+    if (tsx)
+	pjsip_tsx_recv_msg(tsx, rdata);
 
 on_return:
@@ -1143,23 +1145,23 @@
     pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);
 
-    /* Update the remote tag if it is different. */
-    if (pj_strcmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag) != 0) {
-
-	pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
-
-	/* No need to update remote's tag_hval since its never used. */
-    }
-
     /* Keep the response's status code */
     res_code = rdata->msg_info.msg->line.status.code;
 
-    /* When we receive response that establishes dialog, update the route
-     * set and dialog target.
-     */
-    if (!dlg->established && 
+    /* When we receive response that establishes dialog, update To tag, 
+     * route set and dialog target.
+     */
+    if (dlg->state == PJSIP_DIALOG_STATE_NULL && 
 	pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
 	(res_code > 100 && res_code < 300) &&
 	rdata->msg_info.to->tag.slen)
     {
+	pjsip_hdr *hdr, *end_hdr;
+	pjsip_contact_hdr *contact;
+
+	/* Update To tag. */
+	pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+	/* No need to update remote's tag_hval since its never used. */
+
+
 	/* RFC 3271 Section 12.1.2:
 	 * The route set MUST be set to the list of URIs in the Record-Route
@@ -1170,7 +1172,4 @@
 	 * route set for future requests in this dialog.
 	 */
-	pjsip_hdr *hdr, *end_hdr;
-	pjsip_contact_hdr *contact;
-
 	pj_list_init(&dlg->route_set);
 
@@ -1195,5 +1194,5 @@
 	}
 
-	dlg->established = 1;
+	dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
     }
 
@@ -1252,4 +1251,7 @@
 	--dlg->tsx_count;
 
+    /* Increment session to prevent usages from destroying dialog. */
+    ++dlg->sess_count;
+
     /* Pass to dialog usages. */
     for (i=0; i<dlg->usage_cnt; ++i) {
@@ -1260,4 +1262,7 @@
 	(*dlg->usage[i]->on_tsx_state)(tsx, e);
     }
+
+    /* Decrement temporary session. */
+    --dlg->sess_count;
 
     if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 && 
Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 160)
@@ -171,6 +171,4 @@
 static int         tsx_send_msg( pjsip_transaction *tsx, 
                                  pjsip_tx_data *tdata);
-static void	   tsx_on_rx_msg( pjsip_transaction *tsx,
-				  pjsip_rx_data *rdata );
 
 
@@ -698,10 +696,10 @@
     /* Race condition!
      * Transaction may gets deleted before we have chance to lock it
-     * in tsx_on_rx_msg().
+     * in pjsip_tsx_recv_msg().
      */
     PJ_TODO(FIX_RACE_CONDITION_HERE);
 
     /* Pass the message to the transaction. */
-    tsx_on_rx_msg(tsx, rdata );
+    pjsip_tsx_recv_msg(tsx, rdata );
 
     return PJ_TRUE;
@@ -746,10 +744,10 @@
     /* Race condition!
      * Transaction may gets deleted before we have chance to lock it
-     * in tsx_on_rx_msg().
+     * in pjsip_tsx_recv_msg().
      */
     PJ_TODO(FIX_RACE_CONDITION_HERE);
 
     /* Pass the message to the transaction. */
-    tsx_on_rx_msg(tsx, rdata );
+    pjsip_tsx_recv_msg(tsx, rdata );
 
     return PJ_TRUE;
@@ -966,10 +964,5 @@
 	pj_assert(rdata != NULL);
 
-	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG &&
-	    tsx->tsx_user->on_rx_request)
-	{
-	    (*tsx->tsx_user->on_rx_request)(rdata);
-
-	} else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG &&
+	if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG &&
 		   tsx->tsx_user->on_rx_response)
 	{
@@ -1240,9 +1233,9 @@
 
 
-    /* Begin with state TRYING.
+    /* Begin with state NULL.
      * Manually set-up the state becase we don't want to call the callback.
      */
-    tsx->state = PJSIP_TSX_STATE_TRYING; 
-    tsx->state_handler = &tsx_on_state_trying;
+    tsx->state = PJSIP_TSX_STATE_NULL; 
+    tsx->state_handler = &tsx_on_state_null;
 
     /* Get response address. */
@@ -1328,5 +1321,5 @@
 			     state_str[tsx->state]));
 
-    PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata);
+    PJSIP_EVENT_INIT_TX_MSG(event, tdata);
 
     /* Dispatch to transaction. */
@@ -1350,5 +1343,6 @@
  * transaction is received.
  */
-static void tsx_on_rx_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata)
+PJ_DEF(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx, 
+				 pjsip_rx_data *rdata)
 {
     pjsip_event event;
@@ -1363,5 +1357,5 @@
 
     /* Init event. */
-    PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata);
+    PJSIP_EVENT_INIT_RX_MSG(event, rdata);
 
     /* Dispatch to transaction. */
@@ -1717,9 +1711,10 @@
     if (tsx->role == PJSIP_ROLE_UAS) {
 
-	/* UAS doesn't have STATE_NULL.
-	 * State has moved from NULL after transaction is initialized.
-	 */
-	pj_assert(!"Bug bug bug!!");
-	return PJ_EBUG;
+	/* Set state to Trying. */
+	pj_assert(event->type == PJSIP_EVENT_RX_MSG &&
+		  event->body.rx_msg.rdata->msg_info.msg->type == 
+		    PJSIP_REQUEST_MSG);
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG,
+		       event->body.rx_msg.rdata);
 
     } else {
Index: pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 160)
@@ -475,7 +475,12 @@
     pjsip_dialog *dlg;
 
-    /* Optimized path: bail out early if request doesn't have To tag */
-    if (rdata->msg_info.to->tag.slen == 0)
+    /* Optimized path: bail out early if request is not CANCEL and it doesn't
+     * have To tag 
+     */
+    if (rdata->msg_info.to->tag.slen == 0 && 
+	rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)
+    {
 	return PJ_FALSE;
+    }
 
     /* Lock user agent before looking up the dialog hash table. */
@@ -625,5 +630,7 @@
 
     if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) {
-	//pj_str_t *to_tag = &rdata->msg_info.to->tag;
+	
+	int st_code = rdata->msg_info.msg->line.status.code;
+	pj_str_t *to_tag = &rdata->msg_info.to->tag;
 
 	/* Must hold UA mutex before accessing dialog set. */
@@ -632,8 +639,4 @@
 	dlg = dlg_set->dlg_list.next;
 
-	/* Forking handling is temporarily disabled. */
-	PJ_TODO(UA_LAYER_HANDLE_FORKING);
-
-#if 0
 	while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
 
@@ -653,7 +656,10 @@
 
 	/* If no dialog with matching remote tag is found, this must be
-	 * a forked response.
+	 * a forked response. Respond to this ONLY when response is non-100
+	 * provisional response OR a 2xx response.
 	 */
-	if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+	if (dlg == (pjsip_dialog*)&dlg_set->dlg_list &&
+	    ((st_code/100==1 && st_code!=100) || st_code/100==2)) 
+	{
 	    /* Report to application about forked condition.
 	     * Application can either create a dialog or ignore the response.
@@ -678,6 +684,14 @@
 		return PJ_TRUE;
 	    }
+
+	} else if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+
+	    /* For 100 or non-2xx response which has different To tag,
+	     * pass the response to the first dialog.
+	     */
+
+	    dlg = dlg_set->dlg_list.next;
+
 	}
-#endif
 
 	/* Done with the dialog set. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_util.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 160)
@@ -1304,4 +1304,7 @@
     }
 
+    /* Feed the request to the transaction. */
+    pjsip_tsx_recv_msg(tsx, rdata);
+
     /* Send the message. */
     status = pjsip_tsx_send_msg(tsx, tdata);
Index: pjproject/trunk/pjsip/src/pjsua/main.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua/main.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsua/main.c	(revision 160)
@@ -19,12 +19,6 @@
 #include "pjsua.h"
 #include "getopt.h"
-
-
-/* For debugging, disable threading. */
-//#define NO_WORKER_THREAD
-
-#ifdef NO_WORKER_THREAD
-#include <conio.h>
-#endif
+#include <stdlib.h>
+
 
 #define THIS_FILE	"main.c"
@@ -69,4 +63,5 @@
     puts("Console keys:");
     puts("  m    Make a call");
+    puts("  a    Answer incoming call");
     puts("  h    Hangup current call");
     puts("  q    Quit");
@@ -75,9 +70,26 @@
 }
 
+static pj_bool_t input(const char *title, char *buf, pj_size_t len)
+{
+    char *p;
+
+    printf("%s (empty to cancel): ", title); fflush(stdout);
+    fgets(buf, len, stdin);
+
+    /* Remove trailing newlines. */
+    for (p=buf; ; ++p) {
+	if (*p=='\r' || *p=='\n') *p='\0';
+	else if (!*p) break;
+    }
+
+    if (!*buf)
+	return PJ_FALSE;
+    
+    return PJ_TRUE;
+}
+
 static void ui_console_main(void)
 {
-    char keyin[10];
     char buf[128];
-    char *p;
     pjsip_inv_session *inv;
 
@@ -86,16 +98,8 @@
     for (;;) {
 
-#ifdef NO_WORKER_THREAD
-	pj_time_val timeout = { 0, 10 };
-	pjsip_endpt_handle_events (pjsua.endpt, &timeout);
-
-	if (kbhit())
-	    fgets(keyin, sizeof(keyin), stdin);
-#else
 	ui_help();
-	fgets(keyin, sizeof(keyin), stdin);
-#endif
-
-	switch (keyin[0]) {
+	fgets(buf, sizeof(buf), stdin);
+
+	switch (buf[0]) {
 
 	case 'm':
@@ -107,29 +111,42 @@
 
 #if 1
-	    printf("Enter URL to call: "); fflush(stdout);
-	    fgets(buf, sizeof(buf), stdin);
-
-	    if (buf[0]=='\r' || buf[0]=='\n') {
-		/* Cancelled. */
-		puts("<cancelled>");
+	    /* Make call! : */
+	    if (!input("Enter URL to call", buf, sizeof(buf)))
+		continue;
+	    pjsua_invite(buf, &inv);
+
+#else
+
+	    pjsua_invite("sip:localhost:5061", &inv);
+#endif
+	    break;
+
+
+	case 'a':
+
+	    if (inv_session == NULL || inv_session->role != PJSIP_ROLE_UAS ||
+		inv_session->state >= PJSIP_INV_STATE_CONNECTING) 
+	    {
+		puts("No pending incoming call");
 		fflush(stdout);
 		continue;
-	    }
-
-	    /* Remove trailing newlines. */
-	    for (p=buf; ; ++p) {
-		if (*p=='\r' || *p=='\n') *p='\0';
-		else if (!*p) break;
-	    }
-	    /* Make call! : */
-
-	    pjsua_invite(buf, &inv);
-
-#else
-
-	    pjsua_invite("sip:localhost:5061", &inv);
-#endif
-	    break;
-
+
+	    } else {
+		pj_status_t status;
+		pjsip_tx_data *tdata;
+
+		if (!input("Answer with code (100-699)", buf, sizeof(buf)))
+		    continue;
+		
+		status = pjsip_inv_answer(inv_session, atoi(buf), NULL, NULL, 
+					  &tdata);
+		if (status == PJ_SUCCESS)
+		    status = pjsip_inv_send_msg(inv_session, tdata, NULL);
+
+		if (status != PJ_SUCCESS)
+		    pjsua_perror("Unable to create/send response", status);
+	    }
+
+	    break;
 
 	case 'h':
@@ -673,9 +690,4 @@
 
 
-#ifdef NO_WORKER_THREAD
-    pjsua.thread_cnt = 0;
-#endif
-
-
     /* Initialize pjsua (to create pool etc).
      */
Index: pjproject/trunk/pjsip/src/pjsua/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 159)
+++ pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 160)
@@ -102,6 +102,97 @@
 static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
 {
-    PJ_UNUSED_ARG(rdata);
-    PJ_TODO(IMPLEMENT_UAS);
+    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+    pjsip_msg *msg = rdata->msg_info.msg;
+
+    /*
+     * Handle incoming INVITE outside dialog.
+     */
+    if (dlg == NULL && tsx == NULL &&
+	msg->line.req.method.id == PJSIP_INVITE_METHOD)
+    {
+	pj_status_t status;
+	pjsip_tx_data *response = NULL;
+	unsigned options = 0;
+
+	/* Verify that we can handle the request. */
+	status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
+					  pjsua.endpt, &response);
+	if (status != PJ_SUCCESS) {
+
+	    /*
+	     * No we can't handle the incoming INVITE request.
+	     */
+
+	    if (response) {
+		pjsip_response_addr res_addr;
+
+		pjsip_get_response_addr(response->pool, rdata, &res_addr);
+		pjsip_endpt_send_response(pjsua.endpt, &res_addr, response, 
+					  NULL, NULL);
+
+	    } else {
+
+		/* Respond with 500 (Internal Server Error) */
+		pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
+					      NULL, NULL);
+	    }
+
+	} else {
+	    /*
+	     * Yes we can handle the incoming INVITE request.
+	     */
+	    pjsip_inv_session *inv;
+	    pjmedia_sdp_session *answer;
+
+	    /* Create dummy SDP answer: */
+
+
+	    status = pjmedia_sdp_parse(pjsua.pool, PJSUA_DUMMY_SDP_ANSWER,
+				       pj_native_strlen(PJSUA_DUMMY_SDP_ANSWER),
+				       &answer);
+	    if (status != PJ_SUCCESS) {
+
+		pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
+					      NULL, NULL);
+		return PJ_TRUE;
+	    }
+
+	    /* Create dialog: */
+
+	    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
+					   &pjsua.contact_uri, &dlg);
+	    if (status != PJ_SUCCESS)
+		return PJ_TRUE;
+
+
+	    /* Create invite session: */
+
+	    status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
+	    if (status != PJ_SUCCESS) {
+
+		status = pjsip_dlg_create_response( dlg, rdata, 500, NULL,
+						    &response);
+		if (status == PJ_SUCCESS)
+		    status = pjsip_dlg_send_response(dlg, 
+						     pjsip_rdata_get_tsx(rdata),
+						     response);
+		return PJ_TRUE;
+
+	    }
+
+	    /* Answer with 100 (using the dialog, not invite): */
+
+	    status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response);
+	    if (status == PJ_SUCCESS)
+		status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response);
+	}
+
+	/* This INVITE request has been handled. */
+	return PJ_TRUE;
+    }
+
+    
+
     return PJ_FALSE;
 }
@@ -122,5 +213,4 @@
 {
     PJ_UNUSED_ARG(rdata);
-    PJ_TODO(IMPLEMENT_UAS);
     return PJ_FALSE;
 }
Index: pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c	(revision 159)
+++ pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c	(revision 160)
@@ -710,4 +710,5 @@
 		return PJ_TRUE;
 	    }
+	    pjsip_tsx_recv_msg(tsx, rdata);
 
 	    save_key(tsx);
@@ -750,4 +751,5 @@
 		return PJ_TRUE;
 	    }
+	    pjsip_tsx_recv_msg(tsx, rdata);
 
 	    save_key(tsx);
@@ -802,4 +804,5 @@
 	    }
 
+	    pjsip_tsx_recv_msg(tsx, rdata);
 	    save_key(tsx);
 
@@ -883,4 +886,5 @@
 	    }
 
+	    pjsip_tsx_recv_msg(tsx, rdata);
 	    save_key(tsx);
 
@@ -967,4 +971,5 @@
 	    }
 
+	    pjsip_tsx_recv_msg(tsx, rdata);
 	    save_key(tsx);
 	    send_response(rdata, tsx, TEST9_STATUS_CODE);
@@ -1077,4 +1082,5 @@
 	    }
 
+	    pjsip_tsx_recv_msg(tsx, rdata);
 	    save_key(tsx);
 	    
