Index: /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 941)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 942)
@@ -75,4 +75,19 @@
 
 /**
+ * Transaction timeout timer policy, to control the UAC transaction timeout
+ * scheduling (see #pjsip_tsx_set_uac_timeout()).
+ */
+typedef enum pjsip_tsx_timeout_policy
+{
+    PJSIP_TSX_IGNORE_100 = 1,	/**< To make the UAC transaction NOT to cancel
+				     the timeout timer when 100 response is 
+				     received.*/
+    PJSIP_TSX_IGNORE_1xx = 3	/**< To make the UAC transaction NOT to cancel
+				     the timeout timer when any 1xx responses 
+				     are received. */
+} pjsip_tsx_timeout_policy;
+
+
+/**
  * This structure describes SIP transaction object. The transaction object
  * is used to handle both UAS and UAC transaction.
@@ -131,4 +146,7 @@
     pj_timer_entry		timeout_timer;  /**< Timeout timer.         */
 
+    unsigned			msec_timeout;	/**< User set timeout.	    */
+    pjsip_tsx_timeout_policy	timeout_policy;	/**< Timeout policy.	    */
+
     /** Module specific data. */
     void		       *mod_data[PJSIP_MAX_MODULE];
@@ -233,4 +251,44 @@
 
 /**
+ * Set the UAC absolute transaction timeout. Normally UAC transaction will
+ * stop its timeout timer (timer B for INVITE and timer F for non-INVITE
+ * transactions) after a provisional response is received.
+ *
+ * When this timer is set, the transaction's timer B and F will use this
+ * value, and if the \a flag flag is set, the transaction will continue
+ * the scheduling of the timeout timer even when provisional response has
+ * been received.
+ *
+ * Note that this function MUST be called AFTER the transaction has been
+ * created AND BEFORE any request is transmitted.
+ *
+ * @param tsx	    The client/UAC transaction.
+ * @param msec_time The timeout value, in miliseconds. Currently this
+ *		    value must be non-zero (value zero is reserved for
+ *		    future use).
+ * @param flag	    Option flags to control whether the transaction should
+ *		    cancel the timeout timer on arrival of provisional
+ *		    responses (which is yes according to RFC 3261).
+ *		    The valid values are:
+ *		    - PJSIP_TSX_IGNORE_100, to make the UAC transaction
+ *		      NOT to cancel the timeout timer when 100 response
+ *		      is received.
+ *		    - PJSIP_TSX_IGNORE_1xx, to make the UAC transaction
+ *		      NOT to cancel the timeout timer when any 1xx 
+ *		      responses are received.
+ *
+ *		    Note that regardless of the values in the \a flag 
+ *		    argument, the provisional response would still be
+ *		    delivered to transaction user and it will still
+ *		    affect the transaction state. The \a flag flag only
+ *		    changes the behavior of the timeout timer of the
+ *		    transaction.
+ */
+PJ_DECL(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx,
+					       unsigned msec_time,
+					       pjsip_tsx_timeout_policy flag);
+
+
+/**
  * Call this function to manually feed a message to the transaction.
  * For UAS transaction, application MUST call this function after
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 941)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 942)
@@ -1397,4 +1397,21 @@
 
 /*
+ * Set the UAC absolute transaction timeout.
+ */
+PJ_DEF(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx,
+					      unsigned msec_time,
+					      pjsip_tsx_timeout_policy policy)
+{
+    PJ_ASSERT_RETURN(tsx && tsx->role==PJSIP_ROLE_UAC &&
+		     tsx->state==PJSIP_TSX_STATE_NULL, PJ_EINVALIDOP);
+
+    tsx->msec_timeout = msec_time;
+    tsx->timeout_policy = policy;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
  * Set transaction status code and reason.
  */
@@ -1897,8 +1914,20 @@
 
 	/* Start Timer B (or called timer F for non-INVITE) for transaction 
-	 * timeout.
+	 * timeout. If user has configured the timeout value with 
+	 * pjsip_tsx_set_uac_timeout(), use the timeout value there.
 	 */
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-                                    &timeout_timer_val);
+	if (tsx->msec_timeout > 0) {
+	    pj_time_val timeout;
+
+	    timeout.sec = tsx->msec_timeout / 1000;
+	    timeout.msec = tsx->msec_timeout % 1000;
+
+	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
+					&timeout);
+
+	} else {
+	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
+					&timeout_timer_val);
+	}
 
 	/* Start Timer A (or timer E) for retransmission only if unreliable 
@@ -1968,5 +1997,5 @@
     } else if (event->type == PJSIP_EVENT_RX_MSG) {
 	pjsip_msg *msg;
-	//int code;
+	int code;
 
 	/* Get message instance */
@@ -1985,6 +2014,16 @@
 
 
-	/* Cancel timer B (transaction timeout) */
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+	/* Cancel timer B (transaction timeout) but look at the timeout policy
+	 * as set by pjsip_tsx_set_uac_timeout().
+	 */
+	code = msg->line.status.code;
+	if ((code==100 && tsx->timeout_policy==PJSIP_TSX_IGNORE_100) ||
+	    (code<200 && tsx->timeout_policy==PJSIP_TSX_IGNORE_1xx))
+	{
+	    /* Don't cancel the timeout timer */
+	}
+	else {
+	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+	}
 
 	/* Discard retransmission message if it is not INVITE.
@@ -2373,4 +2412,12 @@
 	}
 
+    } else if (event->type == PJSIP_EVENT_TIMER &&
+	       event->body.timer.entry == &tsx->timeout_timer) {
+
+	/* Inform TU. */
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+		       PJSIP_EVENT_TIMER, &tsx->timeout_timer);
+
+
     } else if (tsx->status_code >= 300 && tsx->status_code <= 699) {
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_util_statefull.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_util_statefull.c	(revision 941)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_util_statefull.c	(revision 942)
@@ -30,7 +30,4 @@
 struct tsx_data
 {
-    pj_time_val	    delay;
-    pj_timer_entry  timeout_timer;
-
     void *token;
     void (*cb)(void*, pjsip_event*);
@@ -72,10 +69,4 @@
 	return;
 
-    /* Cancel timer if any */
-    if (tsx_data->timeout_timer.id != 0) {
-	tsx_data->timeout_timer.id = 0;
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx_data->timeout_timer);
-    }
-
     /* Call the callback, if any, and prevent the callback to be called again
      * by clearing the transaction's module_data.
@@ -86,27 +77,4 @@
 	(*tsx_data->cb)(tsx_data->token, event);
     }
-}
-
-
-static void mod_util_on_timeout(pj_timer_heap_t *th, pj_timer_entry *te)
-{
-    pjsip_transaction *tsx = (pjsip_transaction*) te->user_data;
-    struct tsx_data *tsx_data;
-
-    PJ_UNUSED_ARG(th);
-
-    tsx_data = tsx->mod_data[mod_stateful_util.id];
-    if (tsx_data == NULL) {
-	pj_assert(!"Shouldn't happen");
-	return;
-    }
-
-    tsx_data->timeout_timer.id = 0;
-
-    PJ_LOG(4,(tsx->obj_name, "Transaction timed out by user timer (%d.%d sec)",
-	      (int)tsx_data->delay.sec, (int)tsx_data->delay.msec));
-
-    /* Terminate the transaction. This will call mod_util_on_tsx_state() */
-    pjsip_tsx_terminate(tsx, PJSIP_SC_TSX_TIMEOUT);
 }
 
@@ -134,24 +102,11 @@
     }
 
-    tsx_data = pj_pool_zalloc(tsx->pool, sizeof(struct tsx_data));
+    tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct tsx_data));
     tsx_data->token = token;
     tsx_data->cb = cb;
 
     if (timeout >= 0) {
-	tsx_data->delay.sec = 0;
-	tsx_data->delay.msec = timeout;
-	pj_time_val_normalize(&tsx_data->delay);
-
-	tsx_data->timeout_timer.id = PJ_TRUE;
-	tsx_data->timeout_timer.user_data = tsx;
-	tsx_data->timeout_timer.cb = &mod_util_on_timeout;
-	
-	status = pjsip_endpt_schedule_timer(endpt, &tsx_data->timeout_timer, 
-					    &tsx_data->delay);
-	if (status != PJ_SUCCESS) {
-	    pjsip_tsx_terminate(tsx, PJSIP_SC_INTERNAL_SERVER_ERROR);
-	    pjsip_tx_data_dec_ref(tdata);
-	    return status;
-	}
+	status = pjsip_tsx_set_uac_timeout(tsx, timeout, PJSIP_TSX_IGNORE_1xx);
+	pj_assert(status == PJ_SUCCESS);
     }
 
@@ -159,11 +114,6 @@
 
     status = pjsip_tsx_send_msg(tsx, NULL);
-    if (status != PJ_SUCCESS) {
-	if (tsx_data->timeout_timer.id != 0) {
-	    pjsip_endpt_cancel_timer(endpt, &tsx_data->timeout_timer);
-	    tsx_data->timeout_timer.id = PJ_FALSE;
-	}
+    if (status != PJ_SUCCESS)
 	pjsip_tx_data_dec_ref(tdata);
-    }
 
     return status;
