Index: /pjproject/trunk/pjlib/include/pj++/list.hpp
===================================================================
--- /pjproject/trunk/pjlib/include/pj++/list.hpp	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj++/list.hpp	(revision 127)
@@ -64,5 +64,5 @@
 	const_iterator operator++() 
         { 
-            return const_iterator(node_->next); 
+            return const_iterator((const List_Node *)node_->next); 
         }
 	bool operator==(const const_iterator &rhs) 
@@ -100,5 +100,5 @@
 	iterator operator++() 
         { 
-            return iterator(node_->next); 
+            return iterator((List_Node*)node_->next); 
         }
 	bool operator==(const iterator &rhs) 
@@ -122,4 +122,28 @@
 
     //
+    // You can cast Pj_List to pj_list
+    //
+    operator pj_list&()
+    {
+	return (pj_list&)root_;
+    }
+    operator const pj_list&()
+    {
+	return (const pj_list&)root_;
+    }
+
+    //
+    // You can cast Pj_List to pj_list* too
+    //
+    operator pj_list*()
+    {
+	return (pj_list*)&root_;
+    }
+    operator const pj_list*()
+    {
+	return (const pj_list*)&root_;
+    }
+
+    //
     // Check if list is empty.
     // 
@@ -319,5 +343,5 @@
 	// it's because List_Node is not derived from Pj_List_Node.
 	List_Node *n = (List_Node*)0;
-	n = n->next; n = n->prev;
+	n = (List_Node *)n->next; n = (List_Node *)n->prev;
     }
 };
Index: /pjproject/trunk/pjlib/include/pj++/pool.hpp
===================================================================
--- /pjproject/trunk/pjlib/include/pj++/pool.hpp	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj++/pool.hpp	(revision 127)
@@ -124,4 +124,12 @@
 
     //
+    // You can cast Pj_Pool to pj_pool_t*
+    //
+    operator pj_pool_t*()
+    {
+	return p_;
+    }
+
+    //
     // Get pjlib compatible pool object.
     //
Index: /pjproject/trunk/pjlib/include/pj++/string.hpp
===================================================================
--- /pjproject/trunk/pjlib/include/pj++/string.hpp	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj++/string.hpp	(revision 127)
@@ -41,7 +41,7 @@
 
     //
-    // Construct the buffer from a char*.
-    //
-    explicit Pj_String(char *str) 
+    // Construct the buffer from a char* (use with care)
+    //
+    Pj_String(char *str) 
     { 
 	set(str);
@@ -51,5 +51,5 @@
     // Construct from a const char*.
     //
-    Pj_String(Pj_Pool *pool, const char *src)
+    Pj_String(Pj_Pool &pool, const char *src)
     {
 	set(pool, src);
@@ -57,9 +57,19 @@
 
     //
-    // Construct from pj_str_t*.
-    //
-    explicit Pj_String(pj_str_t *s)
-    {
-	set(s);
+    // Construct from pj_str_t&.
+    //
+    explicit Pj_String(pj_str_t &s)
+    {
+	ptr = s.ptr;
+	slen = s.slen;
+    }
+
+    //
+    // Construct from const pj_str_t& (use with care!).
+    //
+    explicit Pj_String(const pj_str_t &s)
+    {
+	ptr = (char*)s.ptr;
+	slen = s.slen;
     }
 
@@ -67,5 +77,5 @@
     // Construct by copying from const pj_str_t*.
     //
-    Pj_String(Pj_Pool *pool, const pj_str_t *s)
+    Pj_String(Pj_Pool &pool, const pj_str_t *s)
     {
 	set(pool, s);
@@ -73,15 +83,7 @@
 
     //
-    // Construct from another Pj_String
-    //
-    explicit Pj_String(Pj_String &rhs)
-    {
-	set(rhs);
-    }
-
-    //
     // Construct by copying from Pj_String
     //
-    Pj_String(Pj_Pool *pool, const Pj_String &rhs)
+    Pj_String(Pj_Pool &pool, const Pj_String &rhs)
     {
 	set(pool, rhs);
@@ -89,4 +91,13 @@
 
     //
+    // Construct from another Pj_String, use with care!
+    //
+    explicit Pj_String(const Pj_String &rhs)
+    {
+	ptr = rhs.ptr;
+	slen = rhs.slen;
+    }
+
+    //
     // Construct from a char* and a length.
     //
@@ -105,4 +116,20 @@
 
     //
+    // You can cast Pj_String to pj_str_t*
+    //
+    operator pj_str_t*()
+    {
+	return this;
+    }
+
+    //
+    // You can cast const Pj_String to const pj_str_t*
+    //
+    operator const pj_str_t*() const
+    {
+	return this;
+    }
+
+    //
     // Get the length of the string.
     //
@@ -139,7 +166,7 @@
     // Initialize by copying from a const char*.
     //
-    void set(Pj_Pool *pool, const char *s)
-    {
-	pj_strdup2(pool->pool_(), this, s);
+    void set(Pj_Pool &pool, const char *s)
+    {
+	pj_strdup2(pool, this, s);
     }
 
@@ -155,7 +182,7 @@
     // Initialize by copying from const pj_str_t*.
     //
-    void set(Pj_Pool *pool, const pj_str_t *s)
-    {
-	pj_strdup(pool->pool_(), this, s);
+    void set(Pj_Pool &pool, const pj_str_t *s)
+    {
+	pj_strdup(pool, this, s);
     }
 
@@ -187,7 +214,7 @@
     // Initialize by copying from a Pj_String*.
     //
-    void set(Pj_Pool *pool, const Pj_String *s)
-    {
-	pj_strdup(pool->pool_(), this, s);
+    void set(Pj_Pool &pool, const Pj_String *s)
+    {
+	pj_strdup(pool, this, s);
     }
 
@@ -195,7 +222,7 @@
     // Initialize by copying from other Pj_String.
     //
-    void set(Pj_Pool *pool, const Pj_String &s)
-    {
-	pj_strdup(pool->pool_(), this, &s);
+    void set(Pj_Pool &pool, const Pj_String &s)
+    {
+	pj_strdup(pool, this, &s);
     }
 
@@ -354,9 +381,10 @@
 
     ///
-    // Assign from another Pj_String
-    //
-    Pj_String& operator=(Pj_String &rhs)
-    {
-	set(rhs);
+    // Assign from another Pj_String, use with care!
+    //
+    Pj_String& operator=(const Pj_String &rhs)
+    {
+	ptr = rhs.ptr;
+	slen = rhs.slen;
 	return *this;
     }
Index: /pjproject/trunk/pjlib/include/pj++/types.hpp
===================================================================
--- /pjproject/trunk/pjlib/include/pj++/types.hpp	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj++/types.hpp	(revision 127)
@@ -157,4 +157,18 @@
 };
 
+//
+// Macro to declare common object comparison operators.
+//
+#define PJ_DECLARE_OPERATORS(rhs_type)			    \
+	    bool operator!=(rhs_type rhs) const {	    \
+		return !operator==(rhs); }		    \
+	    bool operator<=(rhs_type rhs) const {	    \
+		return operator<(rhs) || operator==(rhs); } \
+	    bool operator>(rhs_type rhs) const {	    \
+		return !operator<=(rhs); }		    \
+	    bool operator>=(rhs_type rhs) const {	    \
+		return !operator<(rhs); }
+
+
 #endif	/* __PJPP_TYPES_HPP__ */
 
Index: /pjproject/trunk/pjlib/include/pj/assert.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/assert.h	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj/assert.h	(revision 127)
@@ -50,5 +50,5 @@
 /**
  * @hideinitializer
- * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then 
+ * If #PJ_ENABLE_EXTRA_CHECK is declared and the value is non-zero, then 
  * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during
  * run-time. If the expression yields false, assertion will be triggered
Index: /pjproject/trunk/pjlib/include/pj/hash.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/hash.h	(revision 126)
+++ /pjproject/trunk/pjlib/include/pj/hash.h	(revision 127)
@@ -46,4 +46,9 @@
 
 /**
+ * This indicates the size of of each hash entry.
+ */
+#define PJ_HASH_ENTRY_SIZE	(3*sizeof(void*) + 2*sizeof(pj_uint32_t))
+
+/**
  * This is the function that is used by the hash table to calculate hash value
  * of the specified key.
@@ -93,13 +98,22 @@
  * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the
  *		    string length of the key.
+ * @param hval	    if this argument is not NULL and the value is not zero,
+ *		    the value will be used as the computed hash value. If
+ *		    the argument is not NULL and the value is zero, it will
+ *		    be filled with the computed hash upon return.
  *
  * @return the value associated with the key, or NULL if the key is not found.
  */
 PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
-			     const void *key, unsigned keylen );
-
-
-/**
- * Associate/disassociate a value with the specified key.
+			     const void *key, unsigned keylen,
+			     pj_uint32_t *hval );
+
+
+/**
+ * Associate/disassociate a value with the specified key. If value is not
+ * NULL and entry already exists, the entry's value will be overwritten.
+ * If value is not NULL and entry does not exist, a new one will be created
+ * with the specified pool. Otherwise if value is NULL, entry will be
+ * deleted if it exists.
  *
  * @param pool	    the pool to allocate the new entry if a new entry has to be
@@ -109,10 +123,41 @@
  * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 
  *		    string length of the key.
+ * @param hval	    if the value is not zero, then the hash table will use
+ *		    this value to search the entry's index, otherwise it will
+ *		    compute the key. This value can be obtained when calling
+ *		    #pj_hash_get().
  * @param value	    value to be associated, or NULL to delete the entry with
  *		    the specified key.
  */
 PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
-			   const void *key, unsigned keylen,
+			   const void *key, unsigned keylen, pj_uint32_t hval,
 			   void *value );
+
+
+/**
+ * Associate/disassociate a value with the specified key. This function works
+ * like #pj_hash_set(), except that it doesn't use pool (hence the np -- no 
+ * pool suffix). If new entry needs to be allocated, it will use the entry_buf.
+ *
+ * @param ht	    the hash table.
+ * @param key	    the key.
+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 
+ *		    string length of the key.
+ * @param hval	    if the value is not zero, then the hash table will use
+ *		    this value to search the entry's index, otherwise it will
+ *		    compute the key. This value can be obtained when calling
+ *		    #pj_hash_get().
+ * @param entry_buf Pointer to buffer which will be used for the new entry,
+ *		    when one needs to be created. The buffer must be at least
+ *		    PJ_HASH_ENTRY_SIZE long, and the first PJ_HASH_ENTRY_SIZE
+ *		    bytes of the buffer will be used by the hash table.
+ *		    Application may use the remaining portion of the buffer
+ *		    for its own purpose.
+ * @param value	    value to be associated, or NULL to delete the entry with
+ *		    the specified key.
+ */
+PJ_DECL(void) pj_hash_set_np(pj_hash_table_t *ht,
+			     const void *key, unsigned keylen, 
+			     pj_uint32_t hval, void *entry_buf, void *value);
 
 /**
Index: /pjproject/trunk/pjlib/src/pj/hash.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/hash.c	(revision 126)
+++ /pjproject/trunk/pjlib/src/pj/hash.c	(revision 127)
@@ -23,4 +23,5 @@
 #include <pj/os.h>
 #include <pj/ctype.h>
+#include <pj/assert.h>
 
 /**
@@ -58,5 +59,4 @@
 	    hash = hash * PJ_HASH_MULTIPLIER + *p;
 	}
-	keylen = p - (const unsigned char*)key;
     } else {
 	const unsigned char *p = key,
@@ -89,4 +89,7 @@
     unsigned table_size;
     
+    /* Check that PJ_HASH_ENTRY_SIZE is correct. */
+    PJ_ASSERT_RETURN(sizeof(pj_hash_entry)==PJ_HASH_ENTRY_SIZE, NULL);
+
     h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
     h->count = 0;
@@ -111,22 +114,34 @@
 static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, 
 				   const void *key, unsigned keylen,
-				   void *val)
+				   void *val, pj_uint32_t *hval,
+				   void *entry_buf)
 {
     pj_uint32_t hash;
     pj_hash_entry **p_entry, *entry;
 
-    hash=0;
-    if (keylen==PJ_HASH_KEY_STRING) {
-	const unsigned char *p = key;
-	for ( ; *p; ++p ) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
-	keylen = p - (const unsigned char*)key;
+    if (hval && *hval != 0) {
+	hash = *hval;
     } else {
-	const unsigned char *p = key,
-			    *end = p + keylen;
-	for ( ; p!=end; ++p) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
+	/* This slightly differs with pj_hash_calc() because we need 
+	 * to get the keylen when keylen is PJ_HASH_KEY_STRING.
+	 */
+	hash=0;
+	if (keylen==PJ_HASH_KEY_STRING) {
+	    const unsigned char *p = key;
+	    for ( ; *p; ++p ) {
+		hash = hash * PJ_HASH_MULTIPLIER + *p;
+	    }
+	    keylen = p - (const unsigned char*)key;
+	} else {
+	    const unsigned char *p = key,
+				*end = p + keylen;
+	    for ( ; p!=end; ++p) {
+		hash = hash * PJ_HASH_MULTIPLIER + *p;
+	    }
+	}
+
+	/* Report back the computed hash. */
+	if (hval)
+	    *hval = hash;
     }
 
@@ -137,5 +152,5 @@
     {
 	if (entry->hash==hash && entry->keylen==keylen &&
-	    memcmp(entry->key, key, keylen)==0) 
+	    pj_memcmp(entry->key, key, keylen)==0) 
 	{
 	    break;	
@@ -146,8 +161,19 @@
 	return p_entry;
 
-    /* create a new entry */
-    entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
-    PJ_LOG(6, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, 
-			  pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
+    /* Entry not found, create a new one. 
+     * If entry_buf is specified, use it. Otherwise allocate from pool.
+     */
+    if (entry_buf) {
+	entry = entry_buf;
+    } else {
+	/* Pool must be specified! */
+	PJ_ASSERT_RETURN(pool != NULL, NULL);
+
+	entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
+	PJ_LOG(6, ("hashtbl", 
+		   "%p: New p_entry %p created, pool used=%u, cap=%u", 
+		   ht, entry,  pj_pool_get_used_size(pool), 
+		   pj_pool_get_capacity(pool)));
+    }
     entry->next = NULL;
     entry->hash = hash;
@@ -163,18 +189,21 @@
 
 PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
-			    const void *key, unsigned keylen )
+			    const void *key, unsigned keylen,
+			    pj_uint32_t *hval)
 {
     pj_hash_entry *entry;
-    entry = *find_entry( NULL, ht, key, keylen, NULL);
+
+    if (hval) *hval = 0;
+    entry = *find_entry( NULL, ht, key, keylen, NULL, hval, NULL);
     return entry ? entry->value : NULL;
 }
 
 PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
-			  const void *key, unsigned keylen,
+			  const void *key, unsigned keylen, pj_uint32_t hval,
 			  void *value )
 {
     pj_hash_entry **p_entry;
 
-    p_entry = find_entry( pool, ht, key, keylen, value );
+    p_entry = find_entry( pool, ht, key, keylen, value, &hval, NULL);
     if (*p_entry) {
 	if (value == NULL) {
@@ -187,5 +216,29 @@
 	    /* overwrite */
 	    (*p_entry)->value = value;
-	    PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
+	    PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht, 
+		       *p_entry, value));
+	}
+    }
+}
+
+PJ_DEF(void) pj_hash_set_np( pj_hash_table_t *ht,
+			     const void *key, unsigned keylen, 
+			     pj_uint32_t hval, void *entry_buf, void *value)
+{
+    pj_hash_entry **p_entry;
+
+    p_entry = find_entry( NULL, ht, key, keylen, value, &hval, entry_buf );
+    if (*p_entry) {
+	if (value == NULL) {
+	    /* delete entry */
+	    PJ_LOG(6, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
+	    *p_entry = (*p_entry)->next;
+	    --ht->count;
+	    
+	} else {
+	    /* overwrite */
+	    (*p_entry)->value = value;
+	    PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht, 
+		       *p_entry, value));
 	}
     }
Index: /pjproject/trunk/pjmedia/docs/PJMEDIA.txt
===================================================================
--- /pjproject/trunk/pjmedia/docs/PJMEDIA.txt	(revision 127)
+++ /pjproject/trunk/pjmedia/docs/PJMEDIA.txt	(revision 127)
@@ -0,0 +1,11 @@
+The way PJMEDIA works at the moment is, for each destination party (e.g. remote INVITE party), we have one media "session". For each "m" line in the SDP, PJMEDIA creates one media "stream". If the stream is a bi-directional audio, then for each stream, two media "channels" will be created, so one media channel for each direction.
+
+The two channels in one stream share one instance of "codec". A codec is simple struct that provides encode() and decode() functions. 
+
+The media channels will end up in the appropriate "sound stream". The decoder channel (i.e. RTP receiver) will end up in sound player stream, and the encoder channel (i.e. RTP sender) gets the audio frames from sound recorder stream.
+
+Both sound player and recorder devices (or streams) are active objects (they have their own threads). The media channel only needs to register callback function to be called when audio frames are available (or should be supplied) from/to the sound devices. This approach works very well with DirectSound, or with PortAudio's sound framework.
+
+But with the introduction of jitter buffer, another thread needs to be created for the decoder channel. The thread reads RTP from socket on a periodic basis, and put the frame (still encoded) to jitter buffer. When the sound player callback is called (by sound device), it looks for frame in the jitter buffer (instead of reading RTP socket), decode the frame, and return the PCM frame to the sound player.
+
+Now getting back to the topic why I think this could work as it is for your application.
Index: /pjproject/trunk/pjsip/build/pjsip.dsw
===================================================================
--- /pjproject/trunk/pjsip/build/pjsip.dsw	(revision 126)
+++ /pjproject/trunk/pjsip/build/pjsip.dsw	(revision 127)
@@ -5,4 +5,16 @@
 
 Project: "pjlib"=..\..\pjlib\build\pjlib.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjlib++"="..\..\pjlib\build\pjlib++.dsp" - Package Owner=<4>
 
 Package=<5>
@@ -29,4 +41,16 @@
 
 Project: "pjmedia"=..\..\pjmedia\build\pjmedia.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjsip++"=".\pjsip++.dsp" - Package Owner=<4>
 
 Package=<5>
Index: /pjproject/trunk/pjsip/build/pjsip_core.dsp
===================================================================
--- /pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 126)
+++ /pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 127)
@@ -86,4 +86,71 @@
 
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "Base (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_errno.c
+# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_msg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_parser.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_tel_uri.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_uri.c
+# End Source File
+# End Group
+# Begin Group "Core (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_endpoint.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_util_proxy.c
+# End Source File
+# End Group
+# Begin Group "Transport Layer (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_resolve.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_transport.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_transport_loop.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_transport_udp.c
+# End Source File
+# End Group
+# Begin Group "Authentication (.c)"
+
+# PROP Default_Filter ""
 # Begin Source File
 
@@ -102,55 +169,11 @@
 SOURCE=..\src\pjsip\sip_auth_server.c
 # End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_endpoint.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_errno.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_msg.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_parser.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_resolve.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_tel_uri.c
-# End Source File
+# End Group
+# Begin Group "Transaction Layer (.c)"
+
+# PROP Default_Filter ""
 # Begin Source File
 
 SOURCE=..\src\pjsip\sip_transaction.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_transport.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_transport_loop.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_transport_udp.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_uri.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_util.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjsip\sip_util_proxy.c
 # End Source File
 # Begin Source File
@@ -160,11 +183,43 @@
 # End Source File
 # End Group
+# Begin Group "UA Layer (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_dialog.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_ua_layer.c
+# End Source File
+# End Group
+# End Group
 # Begin Group "Header Files"
 
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=..\include\pjsip_core.h
-# End Source File
+# Begin Group "Base Types (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_config.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_errno.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_types.h
+# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.h)"
+
+# PROP Default_Filter ""
 # Begin Source File
 
@@ -173,4 +228,64 @@
 # Begin Source File
 
+SOURCE=..\include\pjsip\sip_msg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_parser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_tel_uri.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_uri.h
+# End Source File
+# End Group
+# Begin Group "Core (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_endpoint.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_event.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_module.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_util.h
+# End Source File
+# End Group
+# Begin Group "Transport Layer (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_resolve.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_transport.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_transport_loop.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_transport_udp.h
+# End Source File
+# End Group
+# Begin Group "Authentication (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
 SOURCE=..\include\pjsip\sip_auth.h
 # End Source File
@@ -183,71 +298,28 @@
 SOURCE=..\include\pjsip\sip_auth_parser.h
 # End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_config.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_endpoint.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_errno.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_event.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_module.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_msg.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_parser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_private.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_resolve.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_tel_uri.h
-# End Source File
+# End Group
+# Begin Group "Transaction Layer (.h)"
+
+# PROP Default_Filter ""
 # Begin Source File
 
 SOURCE=..\include\pjsip\sip_transaction.h
 # End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_transport.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_transport_loop.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_transport_udp.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_types.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_uri.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\include\pjsip\sip_util.h
+# End Group
+# Begin Group "UA Layer (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_ua_layer.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\include\pjsip.h
 # End Source File
 # End Group
Index: /pjproject/trunk/pjsip/build/pjsip_ua.dsp
===================================================================
--- /pjproject/trunk/pjsip/build/pjsip_ua.dsp	(revision 126)
+++ /pjproject/trunk/pjsip/build/pjsip_ua.dsp	(revision 127)
@@ -88,17 +88,14 @@
 # Begin Source File
 
-SOURCE="..\src\pjsip-ua\sip_dialog.c"
-# End Source File
-# Begin Source File
+SOURCE="..\src\pjsip-ua\sip_reg.c"
 
-SOURCE="..\src\pjsip-ua\sip_reg.c"
-# End Source File
-# Begin Source File
+!IF  "$(CFG)" == "pjsip_ua - Win32 Release"
 
-SOURCE="..\src\pjsip-ua\sip_ua.c"
-# End Source File
-# Begin Source File
+!ELSEIF  "$(CFG)" == "pjsip_ua - Win32 Debug"
 
-SOURCE="..\src\pjsip-ua\sip_ua_private.h"
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
 # End Source File
 # End Group
@@ -108,13 +105,5 @@
 # Begin Source File
 
-SOURCE="..\include\pjsip-ua\sip_dialog.h"
-# End Source File
-# Begin Source File
-
 SOURCE="..\include\pjsip-ua\sip_regc.h"
-# End Source File
-# Begin Source File
-
-SOURCE="..\include\pjsip-ua\sip_ua.h"
 # End Source File
 # End Group
Index: /pjproject/trunk/pjsip/build/test_pjsip.dsp
===================================================================
--- /pjproject/trunk/pjsip/build/test_pjsip.dsp	(revision 126)
+++ /pjproject/trunk/pjsip/build/test_pjsip.dsp	(revision 127)
@@ -90,4 +90,8 @@
 # Begin Source File
 
+SOURCE="..\src\test-pjsip\dlg_core_test.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\test-pjsip\main.c"
 # End Source File
Index: project/trunk/pjsip/include/pjsip-ua/sip_dialog.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-ua/sip_dialog.h	(revision 126)
+++ 	(revision )
@@ -1,635 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#ifndef __PJSIP_DIALOG_H__
-#define __PJSIP_DIALOG_H__
-
-/**
- * @file dialog.h
- * @brief SIP Dialog abstraction
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_auth.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA_DIALOG SIP Dialog
- * @ingroup PJSUA
- * @{
- * \brief
- *   This file contains SIP dialog, a higher level abstraction of SIP session.
- *
- * \par Overview
- * A SIP dialog is an abstraction of communication session between two user 
- * agents that persist for some time. The dialog facilitates sequencing of 
- * messages between the user agents and proper routing of requests between both
- * of them. The dialog represents a context in which to interpret SIP messages.
- * However method independent User Agent processing for requests and responses 
- * outside of a dialog exists, hence a dialog is not necessary for message 
- * processing.
- *
- * A dialog is identified at each User Agent with a dialog Id, which consists 
- * of a Call-Id value, a local tag and a remote tag. 
- *
- * A dialog contains certain pieces of data needed for further message 
- * transmissions within the dialog. This data consists of:
- *  - Dialog Id - used to identify the dialog.
- *  - Local sequence number - used to order requests from the UA to its peer.
- *  - Remote sequence number - used to order requests from its peer to the UA.
- *  - Local URI - the address of the local party.
- *  - Remote URI - the address of the remote party.
- *  - Remote target - the address from the Contact header field of the request 
- *    or response or refresh request or response.
- *  - "secure" boolean - determines if the dialog is secure.
- *  - Route set - an ordered list of URIs. The route set is the list of servers
- *    that need to be traversed to send a request to the peer. 
- *  - Authentication info - array of authentication credentials to be used
- *    by the dialog to authenticate to proxies and servers.
- *
- * \par Manipulating Dialog
- * Application should use functions declared in this file to do something with 
- * the dialog. Among other things, application can:
- *   - create outgoing dialog (#pjsip_dlg_init()).
- *   - sends outgoing invitation (#pjsip_dlg_invite()).
- *   - sends response (provisional and final) to incoming invitation
- *     (#pjsip_dlg_answer())
- *   - disconnect dialog (#pjsip_dlg_disconnect()).
- *   - send other request (#pjsip_dlg_create_request() and #pjsip_dlg_send_msg())
- *
- * \par Getting Dialog's Notification
- * Dialog emits notification about various things that's happening to it (e.g.
- * a message is received, dialog state has changed, etc.). Normally it is in
- * the interest of the application to capture these notifications, by
- * supplying the function to be called when the event occurs in #pjsip_dlg_callback
- * structure, and register this structure to user agent by calling 
- * #pjsip_ua_set_dialog_callback().
- *
- * \par Incoming Invitation
- * Upon receiving a new incoming invitation, user agent will automatically create
- * a new dialog, and inform application via \b pjsip_dlg_callback.
- */
-
-/** Forward declaration for user agent structure. */
-typedef struct pjsip_user_agent pjsip_user_agent;
-
-/** Forward declaration for dialog structure. */
-typedef struct pjsip_dlg pjsip_dlg;
-
-/**
- * \brief Type of events that are reported by the dialog to the application callback
- * function.
- */
-typedef enum pjsip_dlg_event_e
-{
-    /** Dialog state has changed. */
-    PJSIP_DIALOG_EVENT_STATE_CHANGED,
-
-    /** Any mid-call messages (reinvitation, message, etc.). */
-    PJSIP_DIALOG_EVENT_MID_CALL_REQUEST,
-
-    /** Other events (low level events). */
-    PJSIP_DIALOG_EVENT_OTHER,
-
-} pjsip_dlg_event_e;
-
-
-/** 
- * \brief Structure registered by applications to receive dialog notifications 
- * from the User Agent. 
- *
- * Applications registers this structure to get notifications from the User Agent
- * about dialog state changes and other events. Application can set any of
- * the callback function to NULL if it doesn't want to handle the notification,
- * however, setting some callbacks to NULL probably will cause some undesired
- * result (such as setting \b on_incoming to NULL will cause the creation of
- * a lot of dialogs with no owner).
- */
-struct pjsip_dlg_callback
-{
-    /**
-     * This is a low level, uninterpreted callback that is called by framework 
-     * for all kinds of events, such as transaction events, dialog events, etc.
-     * @param dlg	The dialog.
-     * @param dlg_event The type of dialog event.
-     * @param event	The event descriptor.
-     */
-    void (*on_all_events)(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event, 
-			  pjsip_event *event );
-
-    /**
-     * This is a low level callback that is called by the framework when the
-     * underlying transaction is about to send outgoing message. This callback
-     * is provided to allow application to modify the message before it is 
-     * transmitted. 
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that transmits the message.
-     * @param tdata	The transmission data, which contains the message.
-     * @param retransmission The number of times this message has been sent.
-     *			Zero indicates the message is about to be sent the first time,
-     *			one indicates this is the first retransmission, etc.
-     */
-    void (*on_before_tx)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			 pjsip_tx_data *tdata, pj_bool_t retransmission);
-
-    /**
-     * This is a low level callback that is called by the framework when the dialog
-     * has sent a message. Note that a receive of retransmission will not trigger
-     * this callback since retransmission is handled internally by transaction.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that transmits the message.
-     * @param tdata	The transmission data, which contains the message.
-     */
-    void (*on_tx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-		      pjsip_tx_data *tdata);
-
-    /**
-     * This is a low level callback that is called by the framework when the
-     * dialog has received a message. Note that a receipt of retransmission 
-     * will not trigger this callback since retransmission is handled internally
-     * by transaction.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that receives the message.
-     * @param rdata	The receive data, which contains the message.
-     */
-    void (*on_rx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-		      pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called by the framework when the user agent
-     * instance receives an incoming INVITE message.
-     * @param dlg	The new dialog that's just created to handle the incoming call.
-     * @param tsx	The INVITE transaction that's just created.
-     * @param rdata	The receive data, which contains the INVITE message.
-     */
-    void (*on_incoming)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-		        pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called by the framework when the dialog is sending
-     * the first outgoing INVITE message.
-     * @param dlg	The dialog.
-     * @param tsx	The INVITE transaction.
-     * @param tdata	The transmit data, which contains the INVITE message.
-     */
-    void (*on_calling)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-		       pjsip_tx_data *tdata);
-
-    /**
-     * This callback is called by the framework when the initial INVITE
-     * transaction has sent/received provisional response.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction.
-     * @param event	The event, which src_type will always be either
-     *			PJSIP_EVENT_RX_MSG or PJSIP_EVENT_TX_MSG. The provisional
-     *			response message itself will be in either \b rdata or \b tdata.
-     * @see pjsip_event.
-     */
-    void (*on_provisional)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			   pjsip_event *event);
-
-    /**
-     * This callback is called for both UAS and UAC dialog when 200 response
-     * to INVITE is sent or received.
-     * @param dlg	The dialog.
-     * @param event	The event, which src_type can only be either 
-     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
-     * @see pjsip_event
-     */
-    void (*on_connecting)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called for both UAS and UAC when an ACK request is
-     * sent or received by the dialog.
-     * @param dlg	The dialog.
-     * @param event	The event, which src_type can only be either 
-     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
-     * @see pjsip_event
-     */
-    void (*on_established)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called when the dialog is disconnected, i.e. upon
-     * sending/receiving non-200 response to INVITE, sending/receiving
-     * CANCEL to initial INVITE, and sending/receiving BYE.
-     *
-     * @param dlg	The dialog.
-     * @param event	The event.
-     * @see pjsip_event
-     */
-    void (*on_disconnected)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called when the dialog is about to be destroyed.
-     * @param dlg The dialog.
-     */
-    void (*on_terminated)(pjsip_dlg *dlg);
-
-    /**
-     * This callback will be called when the dialog receives mid call events
-     * such as re-invitation or incoming pager.
-     *
-     * @param dlg	The dialog.
-     * @param event	The event.
-     */
-    void (*on_mid_call_events)(pjsip_dlg *dlg, pjsip_event *event);
-
-};  /* struct pjsip_dlg_callback */
-
-
-
-/**
- * Dialog state.
- */
-typedef enum pjsip_dlg_state_e
-{
-    /** 
-     * State NULL is after the dialog is instantiated but before any
-     * initialization is done. 
-     */
-    PJSIP_DIALOG_STATE_NULL,
-
-    /**
-     * State INCOMING is after the (callee) dialog has been initialized with
-     * the incoming request, but before any responses is sent by the dialog.
-     */
-    PJSIP_DIALOG_STATE_INCOMING,
-
-    /**
-     * State CALLING is after the (caller) dialog has sent outgoing invitation
-     * but before any responses are received.
-     */
-    PJSIP_DIALOG_STATE_CALLING,
-
-    /**
-     * State PROCEEDING is after the dialog sent/received provisional 
-     * responses, but before final response is sent/received.
-     */
-    PJSIP_DIALOG_STATE_PROCEEDING,
-
-    /**
-     * State CONNECTING is after the dialog has sent/received final response
-     * to the invitation, but before acknowledgement is sent.
-     */
-    PJSIP_DIALOG_STATE_CONNECTING,
-
-    /**
-     * State ESTABLISHED occurs after the invitation has been accepted and
-     * acknowledged.
-     */
-    PJSIP_DIALOG_STATE_ESTABLISHED,
-
-    /**
-     * State DISCONNECTED occurs after either party successfully disconnect
-     * the session.
-     */
-    PJSIP_DIALOG_STATE_DISCONNECTED,
-
-    /**
-     * State TERMINATE occurs when the dialog is ready to be destroyed.
-     */
-    PJSIP_DIALOG_STATE_TERMINATED,
-
-} pjsip_dlg_state_e;
-
-
-/**
- * Get the dialog string state.
- *
- * @param state	    Dialog state.
- * @return	    The string describing the state.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state);
-
-/**
- * This structure is used to describe dialog's participants, which in this
- * case is local party (i.e. us) and remote party.
- */
-typedef struct pjsip_dlg_party
-{
-    pjsip_uri		*target;    /**< Target URL.			*/
-    pjsip_fromto_hdr	*info;	    /**< URL in From/To header.		*/
-    pj_str_t		 tag;	    /**< Tag.				*/
-    pjsip_contact_hdr	*contact;   /**< URL in Contact.		*/
-    pj_sockaddr_in	 addr;	    /**< The current transport address. */
-    int			 cseq;	    /**< Sequence number counter.	*/
-} pjsip_dlg_party;
-
-
-/**
- * This structure describes the dialog structure.
- */
-struct pjsip_dlg
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_dlg)
-
-    char	        obj_name[PJ_MAX_OBJ_NAME];  /**< Log identification.	*/
-
-    pjsip_user_agent   *ua;			    /**< User agent instance.	*/
-    pj_pool_t	       *pool;			    /**< Dialog's pool.		*/
-    pjsip_dlg_state_e   state;			    /**< Dialog's call state.	*/
-    pjsip_role_e	role;			    /**< Dialog's role.		*/
-    pj_mutex_t	       *mutex;			    /**< Dialog's mutex.	*/
-
-    pjsip_dlg_party     local;			    /**< Local party info.	*/
-    pjsip_dlg_party     remote;			    /**< Remote party info.	*/
-
-    pjsip_cid_hdr      *call_id;		    /**< Call-ID		*/
-    pj_bool_t	        secure;			    /**< Use secure transport?	*/
-
-    pjsip_route_hdr     route_set;		    /**< Dialog's route set.	*/
-    pjsip_transaction  *invite_tsx;		    /**< Current INVITE transaction. */
-    int			pending_tsx_count;	    /**< Total pending tsx count. */
-
-    int			cred_count;		    /**< Number of credentials. */
-    pjsip_cred_info    *cred_info;		    /**< Array of credentials.	*/
-
-    pjsip_auth_session	auth_sess;		    /**< List of auth session. */
-
-    pjsip_msg_body     *body;
-
-    void	       *user_data;		    /**< Application's data.	*/
-
-    int  (*handle_tsx_event)(struct pjsip_dlg *,    /**< Internal state handler.*/
-			     pjsip_transaction *,
-			     pjsip_event *);
-};
-
-
-/**
- * Initialize dialog with local and remote info. This function is normally
- * called after application creates the dialog with #pjsip_ua_create_dialog
- * for UAC dialogs.
- *
- * This function will initialize local and remote info from the URL, generate
- * a globally unique Call-ID, initialize CSeq, and initialize other dialog's
- * internal attributes.
- *
- * @param dlg		The dialog to initialize.
- * @param local_info	URI/name address to be used as local info 
- *			(From and Contact headers).
- * @param remote_info	URI/name address to be used as remote info (To header).
- * @param target	URI for initial remote's target, or NULL to set the
- *			initial target the same as remote_info.
- *
- * @return		zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
-				     const pj_str_t *local_info,
-				     const pj_str_t *remote_info,
-				     const pj_str_t *target);
-
-
-/**
- * Set authentication credentials to be used by this dialog.
- *
- * If authentication credentials are set for the dialog, the dialog will try to
- * perform authentication automatically using the credentials supplied, and 
- * also cache the last Authorization or Proxy-Authorization headers for next 
- * requests.
- * 
- * If none of the credentials are suitable or accepted by remote, then
- * the dialog will just pass the authorization failure response back to
- * application.
- *
- * @param dlg		The dialog.
- * @param count		Number of credentials in the array.
- * @param cred		Array of credentials.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
-					        int count,
-						const pjsip_cred_info cred[]);
-
-/**
- * Override local contact details.
- *
- * Call this function to change the contact details to be advertised in Contact
- * header. Application normally need to call this function for incoming calls
- * before answering the call with 200/OK, because for an incoming dialogs, the
- * initial local contact info are generated from the To header, which is 
- * normally not the appropriate one.
- *
- * @param dlg		The dialog.
- * @param contact	The contact to use.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
-					    const pj_str_t *contact );
-
-
-/**
- * Set initial route set to be used by the dialog. This initial route set
- * governs where and how the initial INVITE request will be routed. This
- * initial route set will be overwritten with the route set found in the
- * 2xx response of INVITE.
- *
- * Application only needs to call this function if it wants to have custom
- * route for individual dialogs. If only a single route for all dialogs is
- * needed, then application can set the global route by calling function
- * #pjsip_endpt_set_proxies().
- *
- * @param dlg		The dialog.
- * @param route_set	The route set list.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
-					      const pjsip_route_hdr *route_set );
-
-
-/**
- * Variation of #pjsip_dlg_set_route_set where the headers will be used
- * as it is (i.e. without cloned).
- *
- * @param dlg		The dialog.
- * @param route_set	The route set list.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
-						 pjsip_route_hdr *route_set);
-
-/**
- * Create initial outgoing INVITE message.
- *
- * This function is just a simple wrapper to #pjsip_dlg_create_request(),
- * so it follows the same rule there. In addition, this function also adds
- * \b Allow header to the outgoing request.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- *
- * @return		The dialog transmit data, or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg );
-
-
-/**
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response. Application can only call this function when there's
- * a pending invitation to be answered.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg	The dialog.
- * @param code	The response code, which can be:
- *		- 100-199 Provisional response (application can issue multiple 
- *                        provisional responses).
- *		- 200-299 To answer the invitation (normally status code 200
- *                        is sent).
- *              - 300-699 To reject the invitation.
- * @return	Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code );
-
-
-/**
- * High level function to create message to disconnect dialog. Depending 
- * on dialog's  state, this function will either create CANCEL, final response,
- * or BYE message. A status code must be supplied, which will be set if dialog 
- * will be transmitting a final response to INVITE.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @param status_code	The status code for disconnection.
- * @return		Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, int status_code);
-
-/**
- * Create CANCEL message to cancel pending outgoing dialog invitation. 
- * Normally application should call #pjsip_dlg_disconnect() instead, because
- * that function will create the correct message regardless of the state of 
- * the dialog. 
- *
- * Application can call this function at anytime after it issues outgoing 
- * invitation and before receiving final response. However, there's no 
- * guarantee that the invitation will be successfully cancelled, since the 
- * CANCEL request and the final response can pass over in the wire. So the 
- * application must prepare to have the dialog connected even after the 
- * dialog is cancelled.
- *
- * The final state of the dialog will be reported in the dialog callback.
- * If the CANCEL request succeeded, then the dialog will be disconnected with
- * status code \a PJSIP_SC_REQUEST_TERMINATED.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. 
- *
- * Upon return of this function, the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @return		The dialog transmit data containing the CANCEL message,
- *			or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg );
-
-
-/**
- * Create BYE message. Application shouldn't normally need to use this function,
- * but rather it's preferable to use #pjsip_dlg_disconnect() instead because
- * that function will work to disconnect the session no matter what the state
- * is.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @return		The BYE message or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg );
-
-/**
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request
- * by calling #pjsip_dlg_send_msg().
- *
- * This function will initialize the request message with dialog's properties
- * as follows:
- *  - the request line is initialized with the method and the target is
- *    initialized from current remote target.
- *  - \b From, \b To, \b Contact, and \b Call-Id headers will be added.
- *  - An initial \b CSeq header will be provided (although the value will be
- *    verified again when the message is actually sent with #pjsip_dlg_send_msg().
- *  - \b Route headers will be added from dialog's route set.
- *  - Authentication headers (\b Authorization or \b Proxy-Authorization) will
- *    be added from dialog's authorization cache.
- *
- * Note that upon return the reference counter of the transmit data
- * will be set to one. When the message is sent, #pjsip_dlg_send_msg() will
- * decrement the reference counter, and when the reference counter reach zero,
- * the message will be deleted.
- *
- * @param dlg		The dialog.
- * @param method	The request method.
- * @param cseq		Specify CSeq, or -1 to let the dialog specify CSeq.
- *
- * @return		Transmit data for the new request.
- *
- * @see pjsip_dlg_send_msg()
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
-						  const pjsip_method *method,
-						  int cseq);
-
-
-/**
- * This function can be called by application to send outgoing message (request
- * or response) to remote party. Note that after calling this function, the
- * transmit data will be deleted regardless of the return status. To prevent
- * deletion, application must increase the reference count, but then it will
- * be responsible to delete this transmit data itself (by decreasing the
- * reference count).
- *
- * @param dlg		The dialog.
- * @param tdata		The transmit data, which contains the request message.
- * @return		zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg,
-					 pjsip_tx_data *tdata );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_DIALOG_H__ */
-
Index: project/trunk/pjsip/include/pjsip-ua/sip_ua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-ua/sip_ua.h	(revision 126)
+++ 	(revision )
@@ -1,79 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#ifndef __PJSIP_SIP_UA_H__
-#define __PJSIP_SIP_UA_H__
-
-/**
- * @file sip_ua.h
- * @brief SIP User Agent Module
- */
-
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA SIP User Agent Stack
- */
-
-/**
- * @defgroup PJSUA_UA SIP User Agent
- * @ingroup PJSUA
- * @{
- * \brief
- *   User Agent manages the interactions between application and SIP dialogs.
- */
-
-/** User agent type. */
-typedef pjsip_module pjsip_user_agent;
-
-
-/**
- * Initialize user agent layer and register it to the specified endpoint.
- *
- * @param endpt		The endpoint where the user agent will be
- *			registered.
- *
- * @return		PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt);
-
-/**
- * Get the instance of the user agent.
- *
- * @return		The user agent module instance.
- */
-PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
-
-/**
- * Destroy the user agent layer.
- *
- * @return		PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJSIP_UA_H__ */
-
Index: /pjproject/trunk/pjsip/include/pjsip.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip.h	(revision 127)
+++ /pjproject/trunk/pjsip/include/pjsip.h	(revision 127)
@@ -0,0 +1,56 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJSIP_H__
+#define __PJSIP_H__
+
+/* Base types. */
+#include <pjsip/sip_types.h>
+#include <pjsip/sip_errno.h>
+
+/* Messaging and parsing. */
+#include <pjsip/sip_uri.h>
+#include <pjsip/sip_tel_uri.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_parser.h>
+
+/* Core */
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_util.h>
+
+/* Transport layer */
+#include <pjsip/sip_transport.h>
+#include <pjsip/sip_transport_udp.h>
+#include <pjsip/sip_transport_loop.h>
+#include <pjsip/sip_resolve.h>
+
+/* Authentication. */
+#include <pjsip/sip_auth.h>
+
+/* Transaction layer. */
+#include <pjsip/sip_transaction.h>
+
+/* UA Layer. */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_dialog.h>
+
+
+#endif	/* __PJSIP_H__ */
+
Index: /pjproject/trunk/pjsip/include/pjsip/sip_auth.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 127)
@@ -188,4 +188,16 @@
 
 
+/**
+ * Clone client initialization session. 
+ *
+ * @param pool		Pool to use.
+ * @param sess		Structure to put the duplicated session.
+ * @param rhs		The client session to be cloned.
+ *
+ * @return		PJ_SUCCESS on success;
+ */
+PJ_DECL(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+					   pjsip_auth_clt_sess *sess,
+					   const pjsip_auth_clt_sess *rhs);
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsip/sip_config.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 127)
@@ -53,4 +53,8 @@
 #define PJSIP_POOL_TSX_INC		256
 #define PJSIP_MAX_TSX_KEY_LEN		(PJSIP_MAX_URL_SIZE*2)
+
+/* User agent. */
+#define PJSIP_POOL_LEN_USER_AGENT	1024
+#define PJSIP_POOL_INC_USER_AGENT	1024
 
 /* Message/URL related constants. */
Index: /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 127)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 127)
@@ -0,0 +1,324 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJSIP_SIP_DIALOG_H__
+#define __PJSIP_SIP_DIALOG_H__
+
+
+/**
+ * @file dialog.h
+ * @brief SIP Dialog abstraction
+ */
+
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_auth.h>
+#include <pjsip/sip_errno.h>
+#include <pj/sock.h>
+#include <pj/assert.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * This structure is used to describe dialog's participants, which in this
+ * case is local party (i.e. us) and remote party.
+ */
+typedef struct pjsip_dlg_party
+{
+    pjsip_fromto_hdr	*info;	    /**< From/To header, inc tag.	*/
+    pj_uint32_t		 tag_hval;  /**< Hashed value of the tag.	*/
+    pjsip_contact_hdr	*contact;   /**< Contact header.		*/
+    pj_int32_t		 first_cseq;/**< First CSeq seen.		*/
+    pj_int32_t		 cseq;	    /**< Next sequence number.		*/
+} pjsip_dlg_party;
+
+
+/**
+ * This structure describes the dialog structure.
+ */
+struct pjsip_dialog
+{
+    /** The dialog set list. */
+    PJ_DECL_LIST_MEMBER(pjsip_dialog);
+
+    /* Dialog's system properties. */
+    char		obj_name[PJ_MAX_OBJ_NAME];  /**< Standard id.	    */
+    pj_pool_t	       *pool;	    /**< Dialog's pool.			    */
+    pj_mutex_t	       *mutex;	    /**< Dialog's mutex.		    */
+    pjsip_user_agent   *ua;	    /**< User agent instance.		    */
+
+    /* The dialog set. */
+    void	       *dlg_set;
+
+    /* Dialog's session properties. */
+    pjsip_uri	       *target;	    /**< Current target.		    */
+    pjsip_dlg_party     local;	    /**< Local party info.		    */
+    pjsip_dlg_party     remote;	    /**< Remote party info.		    */
+    pjsip_role_e	role;	    /**< Initial role.			    */
+    pj_bool_t		secure;	    /**< Use secure transport?		    */
+    pjsip_cid_hdr      *call_id;    /**< Call-ID header.		    */
+    pjsip_route_hdr	route_set;  /**< Route set.			    */
+    pjsip_auth_clt_sess	auth_sess;  /**< Client authentication session.	    */
+
+    /** Session counter. */
+    int			sess_count;
+
+    /** Transaction counter. */
+    int			tsx_count;
+
+    /* Dialog usages. */
+    unsigned		usage_cnt;  /**< Number of registered usages.	    */
+    pjsip_module       *usage[PJSIP_MAX_MODULE]; /**< Array of usages, priority sorted   */
+
+    /** Module specific data. */
+    void	       *mod_data[PJSIP_MAX_MODULE];
+};
+
+
+/**
+ * This utility function returns PJ_TRUE if the specified method is a
+ * dialog creating request. This method property is used to determine
+ * whether Contact header should be included in outgoing request.
+ */
+PJ_DECL(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m);
+
+/**
+ * Create a new dialog and return the instance in p_dlg parameter. 
+ * After creating  the dialog, application can add modules as dialog usages
+ * by calling  #pjsip_dlg_add_usage(). 
+ *
+ * If the request has To tag parameter, dialog's local tag will be initialized 
+ * from this value. Otherwise a globally unique id generator will be invoked to
+ * create dialog's local tag.
+ *
+ * This function also initializes the dialog's route set based on the 
+ * Record-Route headers in the request, if present.
+ *
+ * Note that initially, the session count in the dialog will be initialized 
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+					   const pj_str_t *local_uri,
+					   const pj_str_t *local_contact_uri,
+					   const pj_str_t *remote_uri,
+					   const pj_str_t *target,
+					   pjsip_dialog **p_dlg);
+
+
+/**
+ * Initialize UAS dialog from the information found in the incoming request 
+ * that creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the 
+ * local Contact to contact. If contact is not specified, the local contact 
+ * is initialized from the URI in the To header in the request. 
+ *
+ * Note that initially, the session count in the dialog will be initialized 
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uas(  pjsip_user_agent *ua,
+					    pjsip_rx_data *rdata,
+					    const pj_str_t *contact,
+					    pjsip_dialog **p_dlg);
+
+
+/**
+ * Create a new (forked) dialog on receipt on forked response in rdata. 
+ * The new dialog will be created from original_dlg, except that it will have
+ * new remote tag as copied from the To header in the response. Upon return, 
+ * the new_dlg will have been registered to the user agent. Applications just 
+ * need to add modules as dialog's usages.
+ *
+ * Note that initially, the session count in the dialog will be initialized 
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_fork(const pjsip_dialog *original_dlg,
+				    const pjsip_rx_data *rdata,
+				    pjsip_dialog **new_dlg );
+
+/**
+ * Set dialog's initial route set to route_set list. This can only be called
+ * for UAC dialog, before any request is sent. After dialog has been 
+ * established, the route set can not be changed.
+ *
+ * For UAS dialog,the route set will be initialized in pjsip_dlg_create_uas()
+ * from the Record-Route headers in the incoming request.
+ *
+ * The route_set argument is standard list of Route headers (i.e. with 
+ * sentinel).
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+					      const pjsip_route_hdr *route_set );
+
+/**
+ * Increment the number of sessions in the dialog. Note that initially 
+ * (after created) the dialog has the session counter set to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg );
+
+
+/**
+ * Decrement the number of sessions in the dialog. Once the session counter 
+ * reach zero and there is no pending transaction, the dialog will be 
+ * destroyed. Note that this function may destroy the dialog immediately 
+ * if there is no pending transaction when this function is called.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg );
+
+/**
+ * Add a module as dialog usage, and optionally set the module specific data.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+					  pjsip_module *module,
+					  void *mod_data );
+
+/**
+ * Attach module specific data to the dialog. Application can also set 
+ * the value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg,
+					       int mod_id,
+					       void *data )
+{
+    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+    PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+		     PJ_EINVAL);
+    dlg->mod_data[mod_id] = data;
+    return PJ_SUCCESS;
+}
+
+/**
+ * Get module specific data previously attached to the dialog. Application
+ * can also get value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(void*) pjsip_dlg_get_mod_data(pjsip_dialog *dlg,
+					int mod_id)
+{
+    PJ_ASSERT_RETURN(dlg, NULL);
+    PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+		     NULL);
+    return dlg->mod_data[mod_id];
+}
+
+
+
+/**
+ * Get the dialog instance in the incoming rdata. If an incoming message 
+ * matches an existing dialog, the user agent must have put the matching 
+ * dialog instance in the rdata, or otherwise this function will return 
+ * NULL if the message didn't match any existing dialog.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata );
+
+/**
+ * Get the associated dialog in a transaction.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx );
+
+
+/**
+ * Create a basic/generic request with the specified method and optionally
+ * specify the cseq. Use value -1 for cseq to have the dialog automatically
+ * put next cseq number for the request. Otherwise for some requests, 
+ * e.q. CANCEL and ACK, application must put the CSeq in the original 
+ * INVITE request as the parameter. 
+ *
+ * This function will also put Contact header where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_request(	pjsip_dialog *dlg,
+						const pjsip_method *method,
+						int cseq,
+						pjsip_tx_data **tdata);
+
+
+/**
+ * Send request message to remote peer. If the request is not an ACK request, 
+ * the dialog will send the request statefully, by creating an UAC transaction
+ * and send the request with the transaction. 
+ *
+ * Also when the request is not ACK or CANCEL, the dialog will increment its
+ * local cseq number and update the cseq in the request according to dialog's 
+ * cseq.
+ *
+ * If p_tsx is not null, this argument will be set with the transaction 
+ * instance that was used to send the request.
+ *
+ * This function will decrement the transmit data's reference counter
+ * regardless the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_request (	pjsip_dialog *dlg,
+						pjsip_tx_data *tdata,
+						pjsip_transaction **p_tsx );
+
+
+/**
+ * Create a response message for the incoming request in rdata with status
+ * code st_code and optional status text st_text. This function is different
+ * than endpoint's API #pjsip_endpt_create_response() in that the dialog 
+ * function adds Contact header and Record-Routes headers in the response 
+ * where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_response(	pjsip_dialog *dlg,
+						pjsip_rx_data *rdata,
+						int st_code,
+						const pj_str_t *st_text,
+						pjsip_tx_data **tdata);
+
+
+/**
+ * Modify previously sent response with other status code. Contact header 
+ * will be added when appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_modify_response(	pjsip_dialog *dlg,
+						pjsip_tx_data *tdata,
+						int st_code,
+						const pj_str_t *st_text);
+
+
+/**
+ * Send response message statefully. The transaction instance MUST be the 
+ * transaction that was reported on on_rx_request() callback.
+ *
+ * This function decrements the transmit data's reference counter regardless
+ * the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_response(	pjsip_dialog *dlg,
+						pjsip_transaction *tsx,
+						pjsip_tx_data *tdata);
+
+
+
+/* Receives transaction event (called by user_agent module) */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+			     pjsip_transaction *tsx,
+			     pjsip_event *e );
+
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg,
+			      pjsip_rx_data *rdata );
+
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg,
+			       pjsip_rx_data *rdata );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif	/* __PJSIP_SIP_DIALOG_H__ */
+
Index: /pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h	(revision 127)
@@ -229,4 +229,17 @@
 
 /**
+ * Find transaction in endpoint's transaction table by the transaction's key.
+ * This function normally is only used by modules. The key for a transaction
+ * can be created by calling #pjsip_tsx_create_key.
+ *
+ * @param endpt	    The endpoint instance.
+ * @param key	    Transaction key, as created with #pjsip_tsx_create_key.
+ *
+ * @return	    The transaction, or NULL if it's not found.
+ */
+PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
+					          const pj_str_t *key );
+
+/**
  * Register the transaction to the endpoint's transaction table.
  * Before the transaction is registered, it must have been initialized as
@@ -317,38 +330,76 @@
 			       pjsip_transport **p_transport);
 
-/**
- * Get additional headers to be put in outgoing request message. 
- * This function is normally called by transaction layer when sending outgoing
- * requests.
- * 
- * @param endpt	    The endpoint.
- *
- * @return	    List of additional headers to be put in outgoing requests.
- */
-PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt);
-
-/**
- * Get "Allow" header from endpoint. The endpoint builds the "Allow" header
- * from the list of methods supported by modules.
- *
- * @param endpt	    The endpoint.
- *
- * @return	    "Allow" header, or NULL if endpoint doesn't have "Allow" header.
- */
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt );
-
-
-/**
- * Find transaction in endpoint's transaction table by the transaction's key.
- * This function normally is only used by modules. The key for a transaction
- * can be created by calling #pjsip_tsx_create_key.
- *
- * @param endpt	    The endpoint instance.
- * @param key	    Transaction key, as created with #pjsip_tsx_create_key.
- *
- * @return	    The transaction, or NULL if it's not found.
- */
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
-					          const pj_str_t *key );
+
+/*****************************************************************************
+ *
+ * Capabilities Management
+ *
+ * Modules may implement new capabilities to the stack. These capabilities
+ * are indicated by the appropriate SIP header fields, such as Accept,
+ * Accept-Encoding, Accept-Language, Allow, Supported, etc.
+ *
+ * When a module provides new capabilities to the stack, it registers these
+ * capabilities to the endpoint by supplying new tags (strings) to the
+ * appropriate header fields. Application (or other modules) can then query
+ * these header fields to get the list of supported capabilities, and may
+ * include these headers in the outgoing message.
+ *****************************************************************************
+ */
+
+/**
+ * Get the value of the specified capability header field.
+ *
+ * @param endpt	    The endpoint.
+ * @param htype	    The header type to be retrieved, which value may be:
+ *		    - PJSIP_H_ACCEPT
+ *		    - PJSIP_H_ALLOW
+ *		    - PJSIP_H_SUPPORTED
+ * @param hname	    If htype specifies PJSIP_H_OTHER, then the header name
+ *		    must be supplied in this argument. Otherwise the value
+ *		    must be set to NULL.
+ *
+ * @return	    The appropriate header, or NULL if the header is not
+ *		    available.
+ */
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+						      int htype,
+						      const pj_str_t *hname);
+
+
+/**
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
+ *
+ * @param endpt	    The endpoint.
+ * @param mod	    The module which registers the capability.
+ * @param htype	    The header type to be set, which value may be:
+ *		    - PJSIP_H_ACCEPT
+ *		    - PJSIP_H_ALLOW
+ *		    - PJSIP_H_SUPPORTED
+ * @param hname	    If htype specifies PJSIP_H_OTHER, then the header name
+ *		    must be supplied in this argument. Otherwise the value
+ *		    must be set to NULL.
+ * @param count	    The number of tags in the array.
+ * @param tags	    Array of tags describing the capabilities or extensions
+ *		    to be added to the appropriate header.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+						 pjsip_module *mod,
+						 int htype,
+						 const pj_str_t *hname,
+						 unsigned count,
+						 const pj_str_t tags[]);
+
+/**
+ * Get list of additional headers to be put in outgoing request message.
+ *
+ * @param e	    The endpoint.
+ *
+ * @return	    List of headers.
+ */
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *e);
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsip/sip_errno.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 127)
@@ -141,4 +141,9 @@
 /**
  * @hideinitializer
+ * General Invalid URI error.
+ */
+#define PJSIP_EINVALIDURI	(PJSIP_ERRNO_START_PJSIP + 39)	/* 171039 */
+/**
+ * @hideinitializer
  * Unsupported URL scheme.
  */
@@ -348,4 +353,15 @@
 
 
+/************************************************************
+ * UA AND DIALOG ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Missing From/To tag.
+ */
+#define PJSIP_EMISSINGTAG	 (PJSIP_ERRNO_START_PJSIP+120)	/* 171120 */
+
+
+
 PJ_END_DECL
 
Index: /pjproject/trunk/pjsip/include/pjsip/sip_module.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_module.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_module.h	(revision 127)
@@ -25,4 +25,5 @@
  */
 #include <pjsip/sip_types.h>
+#include <pj/list.h>
 
 PJ_BEGIN_DECL
@@ -67,14 +68,4 @@
      */
     void *user_data;
-
-    /**
-     * Number of methods supported by this module.
-     */
-    int method_cnt;
-
-    /**
-     * Array of methods supported by this module.
-     */
-    const pjsip_method *methods[8];
 
     /**
Index: /pjproject/trunk/pjsip/include/pjsip/sip_msg.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_msg.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_msg.h	(revision 127)
@@ -174,46 +174,46 @@
      */
     PJSIP_H_ACCEPT,
-    PJSIP_H_ACCEPT_ENCODING_UNIMP,
-    PJSIP_H_ACCEPT_LANGUAGE_UNIMP,
-    PJSIP_H_ALERT_INFO_UNIMP,
+    PJSIP_H_ACCEPT_ENCODING_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_ACCEPT_LANGUAGE_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_ALERT_INFO_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_ALLOW,
-    PJSIP_H_AUTHENTICATION_INFO_UNIMP,
+    PJSIP_H_AUTHENTICATION_INFO_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_AUTHORIZATION,
     PJSIP_H_CALL_ID,
-    PJSIP_H_CALL_INFO_UNIMP,
+    PJSIP_H_CALL_INFO_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_CONTACT,
-    PJSIP_H_CONTENT_DISPOSITION_UNIMP,
-    PJSIP_H_CONTENT_ENCODING_UNIMP,
-    PJSIP_H_CONTENT_LANGUAGE_UNIMP,
+    PJSIP_H_CONTENT_DISPOSITION_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_CONTENT_ENCODING_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_CONTENT_LANGUAGE_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_CONTENT_LENGTH,
     PJSIP_H_CONTENT_TYPE,
     PJSIP_H_CSEQ,
-    PJSIP_H_DATE_UNIMP,
-    PJSIP_H_ERROR_INFO_UNIMP,
+    PJSIP_H_DATE_UNIMP,			/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_ERROR_INFO_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_EXPIRES,
     PJSIP_H_FROM,
-    PJSIP_H_IN_REPLY_TO_UNIMP,
+    PJSIP_H_IN_REPLY_TO_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_MAX_FORWARDS,
-    PJSIP_H_MIME_VERSION_UNIMP,
+    PJSIP_H_MIME_VERSION_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_MIN_EXPIRES,
-    PJSIP_H_ORGANIZATION_UNIMP,
-    PJSIP_H_PRIORITY_UNIMP,
+    PJSIP_H_ORGANIZATION_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_PRIORITY_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_PROXY_AUTHENTICATE,
     PJSIP_H_PROXY_AUTHORIZATION,
-    PJSIP_H_PROXY_REQUIRE_UNIMP,
+    PJSIP_H_PROXY_REQUIRE_UNIMP,	/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_RECORD_ROUTE,
-    PJSIP_H_REPLY_TO_UNIMP,
+    PJSIP_H_REPLY_TO_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_REQUIRE,
     PJSIP_H_RETRY_AFTER,
     PJSIP_H_ROUTE,
-    PJSIP_H_SERVER_UNIMP,
-    PJSIP_H_SUBJECT_UNIMP,
+    PJSIP_H_SERVER_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
+    PJSIP_H_SUBJECT_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_SUPPORTED,
-    PJSIP_H_TIMESTAMP_UNIMP,
+    PJSIP_H_TIMESTAMP_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_TO,
     PJSIP_H_UNSUPPORTED,
-    PJSIP_H_USER_AGENT_UNIMP,
+    PJSIP_H_USER_AGENT_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_VIA,
-    PJSIP_H_WARNING_UNIMP,
+    PJSIP_H_WARNING_UNIMP,		/* N/A, use pjsip_generic_string_hdr */
     PJSIP_H_WWW_AUTHENTICATE,
 
@@ -749,4 +749,47 @@
 				    char *buf, pj_size_t size);
 
+
+/*
+ * Some usefull macros to find common headers.
+ */
+
+
+/**
+ * Find Call-ID header.
+ *
+ * @param msg	The message.
+ * @return	Call-ID header instance.
+ */
+#define PJSIP_MSG_CID_HDR(msg) \
+	    ((pjsip_cid_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL))
+
+/**
+ * Find CSeq header.
+ *
+ * @param msg	The message.
+ * @return	CSeq header instance.
+ */
+#define PJSIP_MSG_CSEQ_HDR(msg) \
+	    ((pjsip_cseq_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL))
+
+/**
+ * Find From header.
+ *
+ * @param msg	The message.
+ * @return	From header instance.
+ */
+#define PJSIP_MSG_FROM_HDR(msg) \
+	    ((pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL))
+
+/**
+ * Find To header.
+ *
+ * @param msg	The message.
+ * @return	To header instance.
+ */
+#define PJSIP_MSG_TO_HDR(msg) \
+	    ((pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL))
+
+
 /**
  * @}
@@ -767,6 +810,8 @@
 typedef struct pjsip_generic_string_hdr
 {
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr); /**< Standard header field. */
-    pj_str_t hvalue;				    /**< hvalue */
+    /** Standard header field. */
+    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr);
+    /** hvalue */
+    pj_str_t hvalue;
 } pjsip_generic_string_hdr;
 
@@ -779,23 +824,36 @@
  * @param hname	    The header name to be assigned to the header, or NULL to
  *		    assign the header name with some string.
+ * @param hvalue    Optional string to be assigned as the value.
  *
  * @return	    The header, or THROW exception.
  */
-PJ_DECL(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool, 
-						      const pj_str_t *hname );
-
-/**
- * Create a generic header along with the text content.
- *
- * @param pool	    The pool.
- * @param hname	    The header name.
- * @param hvalue    The header text content.
- *
- * @return	    The header instance.
- */
 PJ_DECL(pjsip_generic_string_hdr*) 
-pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
-					   const pj_str_t *hname,
-					   const pj_str_t *hvalue);
+pjsip_generic_string_hdr_create( pj_pool_t *pool, 
+				 const pj_str_t *hname,
+				 const pj_str_t *hvalue);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param hname	    The header name to be assigned to the header, or NULL to
+ *		    assign the header name with some string later.
+ * @param hvalue    Optional string to be assigned as the value.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_generic_string_hdr*) 
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+			       void *mem,
+			       const pj_str_t *hname,
+			       const pj_str_t *hvalue);
+
 
 /**
@@ -828,23 +886,34 @@
  * @param hname	    The header name to be assigned to the header, or NULL to
  *		    assign the header name with some string.
+ * @param hvalue    The value to be assigned to the header.
  *
  * @return	    The header, or THROW exception.
  */
-PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool, 
-						      const pj_str_t *hname );
-
-/**
- * Create a generic header along with the value.
- *
- * @param pool	    The pool.
- * @param hname	    The header name.
- * @param value     The header value content.
- *
- * @return	    The header instance.
- */
-PJ_DECL(pjsip_generic_int_hdr*) 
-pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
-					 const pj_str_t *hname,
-					 int value);
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+						      const pj_str_t *hname,
+						      int hvalue );
+
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param hname	    The header name to be assigned to the header, or NULL to
+ *		    assign the header name with some string later.
+ * @param value	    Value to be assigned to the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init( pj_pool_t *pool,
+							    void *mem,
+							    const pj_str_t *hname,
+							    int value );
 
 /**
@@ -874,9 +943,31 @@
  *
  * @param pool	    Pool to allocate memory from.
+ * @param hname	    Header name.
  *
  * @return	    New generic array header.
  */
-PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_create(pj_pool_t *pool,
-							     const pj_str_t *hnames);
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create(pj_pool_t *pool,
+							     const pj_str_t *hname);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param hname	    The header name to be assigned to the header, or NULL to
+ *		    assign the header name with some string later.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init(pj_pool_t *pool,
+							       void *mem,
+							       const pj_str_t *hname);
+
 
 /**
@@ -906,4 +997,20 @@
 PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool);
 
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+						  void *mem );
 
 /**
@@ -929,4 +1036,22 @@
 PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool);
 
+
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+						void *mem );
 
 /**
@@ -962,4 +1087,22 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+					    void *mem );
+
+
+/**
  * @}
  */
@@ -988,4 +1131,22 @@
  */
 PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool );
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+					      void *mem );
+
 
 /**
@@ -1017,4 +1178,21 @@
  */
 PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool );
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+					      void *mem );
 
 /**
@@ -1055,4 +1233,21 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+						    void *mem );
+
+/**
  * @}
  */
@@ -1084,4 +1279,21 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+						void *mem );
+
+/**
  * @}
  */
@@ -1100,8 +1312,31 @@
  * Create a new Expires header.
  *
- * @param pool	The pool.
- * @return	A new Expires header.
- */
-PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool );
+ * @param pool	    The pool.
+ * @param value	    The expiration value.
+ *
+ * @return	    A new Expires header.
+ */
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+						      int value);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param value	    The expiration value.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+						    void *mem,
+						    int value );
+
 
 /**
@@ -1142,4 +1377,21 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+					      void *mem );
+
+/**
  * Create a To header.
  *
@@ -1150,4 +1402,21 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+					  void *mem );
+
+/**
  * Convert the header to a From header.
  *
@@ -1155,5 +1424,5 @@
  * @return	"From" header.
  */
-PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr );
 
 /**
@@ -1163,5 +1432,5 @@
  * @return	"To" header.
  */
-PJ_DECL(pjsip_to_hdr*)   pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_to_hdr*)   pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr );
 
 /**
@@ -1177,5 +1446,5 @@
  * @{
  */
-typedef pjsip_generic_int_hdr pjsip_max_forwards_hdr;
+typedef pjsip_generic_int_hdr pjsip_max_fwd_hdr;
 
 /**
@@ -1183,9 +1452,29 @@
  *
  * @param pool	    The pool.
+ * @param value	    The Max-Forwards value.
  *
  * @return	    New Max-Forwards header instance.
  */
-PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
-
+PJ_DECL(pjsip_max_fwd_hdr*) 
+pjsip_max_fwd_hdr_create(pj_pool_t *pool, int value);
+
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param value	    The Max-Forwards value.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_max_fwd_hdr*) 
+pjsip_max_fwd_hdr_init( pj_pool_t *pool, void *mem, int value );
 
 /**
@@ -1204,12 +1493,33 @@
 
 /**
- * Create new Max-Forwards header instance.
+ * Create new Min-Expires header instance.
  *
  * @param pool	    The pool.
- *
- * @return	    New Max-Forwards header instance.
- */
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool);
-
+ * @param value	    The Min-Expires value.
+ *
+ * @return	    New Min-Expires header instance.
+ */
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+							     int value);
+
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param value	    The Min-Expires value.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+							    void *mem,
+							    int value );
 
 /**
@@ -1250,4 +1560,21 @@
 PJ_DECL(pjsip_rr_hdr*)	    pjsip_rr_hdr_create( pj_pool_t *pool );
 
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+					  void *mem );
+
 /** 
  * Create new Route header from the pool. 
@@ -1258,4 +1585,21 @@
 PJ_DECL(pjsip_route_hdr*)   pjsip_route_hdr_create( pj_pool_t *pool );
 
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+					        void *mem );
+
 /** 
  * Convert generic routing header to Record-Route header. 
@@ -1296,4 +1640,20 @@
 PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool);
 
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the 
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+						    void *mem );
 
 /**
@@ -1315,8 +1675,24 @@
  *
  * @param pool	    The pool.
+ * @param value	    The Retry-After value.
  *
  * @return	    New Retry-After header instance.
  */
-PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+							     int value);
+
+/**
+ * Initialize a preallocated memory with the header structure. 
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ * @param value	    The Retry-After value.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+							    void *mem,
+							    int value );
 
 
@@ -1343,4 +1719,15 @@
 PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool);
 
+/**
+ * Initialize a preallocated memory with the header structure. 
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+							void *mem );
 
 /**
@@ -1366,4 +1753,15 @@
 PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool);
 
+/**
+ * Initialize a preallocated memory with the header structure. 
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+							    void *mem );
 
 /**
@@ -1409,4 +1807,16 @@
 
 /**
+ * Initialize a preallocated memory with the header structure. 
+ *
+ * @param pool	    Pool for additional memory allocation if required.
+ * @param mem	    Pre-allocated memory to be initialized as the header.
+ *
+ * @return	    The header instance, which points to the same memory 
+ *		    location as the mem argument.
+ */
+PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+					    void *mem );
+
+/**
  * @}
  */
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 127)
@@ -76,4 +76,5 @@
     int				cseq;           /**< The CSeq               */
     pj_str_t			transaction_key;/**< Hash table key.        */
+    pj_uint32_t			hashed_key;	/**< Key's hashed value.    */
     pj_str_t			branch;         /**< The branch Id.         */
 
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transport.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 127)
@@ -68,4 +68,10 @@
 
 /**
+ * Check if transport tp is secure.
+ */
+#define PJSIP_TRANSPORT_IS_SECURE(tp)	    \
+	    ((tp)->flag & PJSIP_TRANSPORT_SECURE)
+
+/**
  * Get the transport type from the transport name.
  *
@@ -234,5 +240,5 @@
 
 	/** Max forwards header. */
-	pjsip_max_forwards_hdr	*max_fwd;
+	pjsip_max_fwd_hdr	*max_fwd;
 
 	/** The first route header. */
Index: /pjproject/trunk/pjsip/include/pjsip/sip_types.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_types.h	(revision 127)
@@ -103,4 +103,9 @@
 
 /**
+ * Forward declaration for SIP method (sip_msg.h)
+ */
+typedef struct pjsip_method pjsip_method;
+
+/**
  * Opaque data type for the resolver engine (sip_resolve.h).
  */
@@ -117,4 +122,16 @@
  */
 typedef struct pjsip_module pjsip_module;
+
+
+/** 
+ * Forward declaration for user agent type (sip_ua_layer.h). 
+ */
+typedef pjsip_module pjsip_user_agent;
+
+/**
+ * Forward declaration for dialog (sip_dialog.h).
+ */
+typedef struct pjsip_dialog pjsip_dialog;
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h	(revision 127)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h	(revision 127)
@@ -0,0 +1,104 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJSIP_SIP_UA_LAYER_H__
+#define __PJSIP_SIP_UA_LAYER_H__
+
+/**
+ * @file sip_ua_layer.h
+ * @brief SIP User Agent Layer Module
+ */
+#include <pjsip/sip_types.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJSUA SIP User Agent Stack
+ */
+
+/**
+ * @defgroup PJSUA_UA SIP User Agent Module
+ * @ingroup PJSUA
+ * @{
+ * \brief
+ *   User Agent manages the interactions between application and SIP dialogs.
+ */
+
+/** User agent initialization parameter. */
+typedef struct pjsip_ua_init_param
+{
+    pjsip_dialog* (*on_dlg_forked)(pjsip_dialog *first_set, pjsip_rx_data *res);
+} pjsip_ua_init_param;
+
+/**
+ * Initialize user agent layer and register it to the specified endpoint.
+ *
+ * @param endpt		The endpoint where the user agent will be
+ *			registered.
+ * @param prm		UA initialization parameter.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt,
+				   const pjsip_ua_init_param *prm);
+
+/**
+ * Get the instance of the user agent.
+ *
+ * @return		The user agent module instance.
+ */
+PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
+
+/**
+ * Destroy the user agent layer.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
+
+/**
+ * Get the endpoint instance of a user agent module.
+ *
+ * @param ua		The user agent instance.
+ *
+ * @return		The endpoint instance where the user agent is
+ *			registered.
+ */
+PJ_DECL(pjsip_endpoint*) pjsip_ua_get_endpt(pjsip_user_agent *ua);
+
+
+/*
+ * Internal.
+ */
+
+PJ_DECL(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+					    pjsip_dialog *dlg );
+PJ_DECL(pj_status_t) pjsip_ua_unregister_dlg(pjsip_user_agent *ua,
+					     pjsip_dialog *dlg );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif	/* __PJSIP_SIP_UA_LAYER_H__ */
+
Index: /pjproject/trunk/pjsip/include/pjsip/sip_uri.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_uri.h	(revision 126)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_uri.h	(revision 127)
@@ -162,7 +162,7 @@
      * @return the length printed.
      */
-    int	(*p_print)(pjsip_uri_context_e context,
-		   const void *uri, 
-		   char *buf, pj_size_t size);
+    pj_ssize_t (*p_print)(pjsip_uri_context_e context,
+			  const void *uri, 
+		          char *buf, pj_size_t size);
 
     /** 
@@ -333,5 +333,5 @@
  * @return SIP URL.
  */
-PJ_DECL(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure );
+PJ_DECL(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure );
 
 /**
@@ -340,5 +340,5 @@
  * @return	    SIPS URL.
  */
-PJ_DECL(pjsip_sip_uri*) pjsips_url_create( pj_pool_t *pool );
+PJ_DECL(pjsip_sip_uri*) pjsip_sips_uri_create( pj_pool_t *pool );
 
 /**
@@ -346,5 +346,5 @@
  * @param url	    The URL.
  */
-PJ_DECL(void)  pjsip_url_init(pjsip_sip_uri *url, int secure);
+PJ_DECL(void)  pjsip_sip_uri_init(pjsip_sip_uri *url, int secure);
 
 /**
@@ -354,6 +354,6 @@
  * @param rhs	    The source URL.
  */
-PJ_DECL(void)  pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url, 
-				const pjsip_sip_uri *rhs);
+PJ_DECL(void)  pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url, 
+				    const pjsip_sip_uri *rhs);
 
 /**
Index: project/trunk/pjsip/include/pjsip_core.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip_core.h	(revision 126)
+++ 	(revision )
@@ -1,40 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#ifndef __PJSIP_CORE_H__
-#define __PJSIP_CORE_H__
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_auth.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_errno.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_tel_uri.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_transport_udp.h>
-#include <pjsip/sip_transport_loop.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
-
-#endif	/* __PJSIP_CORE_H__ */
-
Index: project/trunk/pjsip/src/pjsip-ua/sip_dialog.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_dialog.c	(revision 126)
+++ 	(revision )
@@ -1,1802 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_parser.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/guid.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-
-/* TLS to keep dialog lock record (initialized by UA) */
-int pjsip_dlg_lock_tls_id;
-
-struct dialog_lock_data
-{
-    struct dialog_lock_data *prev;
-    pjsip_dlg	    *dlg;
-    int			     is_alive;
-};
-
-/*
- * Static function prototypes.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
-				      pjsip_dlg *dlg,
-				      const pjsip_method *method,
-				      int cseq );
-static int  dlg_on_all_state_pre(  pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_all_state_post( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_state_null( pjsip_dlg *dlg, 
-			       pjsip_transaction *tsx,
-			       pjsip_event *event);
-static int  dlg_on_state_incoming( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_state_calling( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event);
-static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event);
-static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event);
-static int  dlg_on_state_connecting( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-static int  dlg_on_state_established( pjsip_dlg *dlg, 
-				      pjsip_transaction *tsx,
-				      pjsip_event *event);
-static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 
-				       pjsip_transaction *tsx,
-				       pjsip_event *event);
-static int  dlg_on_state_terminated( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-
-/*
- * Dialog state handlers.
- */
-static int  (*dlg_state_handlers[])(struct pjsip_dlg *, pjsip_transaction *,
-				    pjsip_event *) = 
-{
-    &dlg_on_state_null,
-    &dlg_on_state_incoming,
-    &dlg_on_state_calling,
-    &dlg_on_state_proceeding,
-    &dlg_on_state_connecting,
-    &dlg_on_state_established,
-    &dlg_on_state_disconnected,
-    &dlg_on_state_terminated,
-};
-
-/*
- * Dialog state names.
- */
-static const char* dlg_state_names[] = 
-{
-    "STATE_NULL",
-    "STATE_INCOMING",
-    "STATE_CALLING",
-    "STATE_PROCEEDING",
-    "STATE_CONNECTING",
-    "STATE_ESTABLISHED",
-    "STATE_DISCONNECTED",
-    "STATE_TERMINATED",
-};
-
-
-/*
- * Get the dialog string state, normally for logging purpose.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state)
-{
-    return dlg_state_names[state];
-}
-
-/* Lock dialog mutex. */
-static void lock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
-    struct dialog_lock_data *prev;
-
-    pj_mutex_lock(dlg->mutex);
-    prev = pj_thread_local_get(pjsip_dlg_lock_tls_id);
-    lck->prev = prev;
-    lck->dlg = dlg;
-    lck->is_alive = 1;
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck);
-}
-
-/* Carefully unlock dialog mutex, protect against situation when the dialog
- * has already been destroyed.
- */
-static pj_status_t unlock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
-    pj_assert(pj_thread_local_get(pjsip_dlg_lock_tls_id) == lck);
-    pj_assert(dlg == lck->dlg);
-
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck->prev);
-    if (lck->is_alive)
-	pj_mutex_unlock(dlg->mutex);
-
-    return lck->is_alive ? 0 : -1;
-}
-
-/*
- * This is called by dialog's FSM to change dialog's state.
- */
-static void dlg_set_state( pjsip_dlg *dlg, pjsip_dlg_state_e state,
-			   pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    PJ_LOG(4, (dlg->obj_name, "State %s-->%s (ev=%s, src=%s, data=%p)", 
-	       pjsip_dlg_state_str(dlg->state), pjsip_dlg_state_str(state),
-	       event ? pjsip_event_str(event->type) : "", 
-	       event ? pjsip_event_str(event->src_type) : "",
-	       event ? event->src.data : NULL));
-
-    dlg->state = state;
-    dlg->handle_tsx_event = dlg_state_handlers[state];
-}
-
-/*
- * Invoke dialog's callback.
- * This function is called by dialog's FSM, and interpret the event and call
- * the corresponding callback registered by application.
- */
-static void dlg_call_dlg_callback( pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
-				   pjsip_event *event )
-{
-    pjsip_dlg_callback *cb = dlg->ua->dlg_cb;
-    if (!cb) {
-	PJ_LOG(4,(dlg->obj_name, "Can not call callback (none registered)."));
-	return;
-    }
-
-    /* Low level event: call the all-events callback. */
-    if (cb->on_all_events) {
-	(*cb->on_all_events)(dlg, dlg_event, event);
-    }
-
-    /* Low level event: call the tx/rx callback if this is a tx/rx event. */
-    if (event->type == PJSIP_EVENT_BEFORE_TX && cb->on_before_tx)
-    {
-	(*cb->on_before_tx)(dlg, event->obj.tsx, event->src.tdata, event->data.long_data);
-    }
-    else if (event->type == PJSIP_EVENT_TX_MSG && 
-	event->src_type == PJSIP_EVENT_TX_MSG && cb->on_tx_msg) 
-    {
-	(*cb->on_tx_msg)(dlg, event->obj.tsx, event->src.tdata);
-    } 
-    else if (event->type == PJSIP_EVENT_RX_MSG &&
-	     event->src_type == PJSIP_EVENT_RX_MSG && cb->on_rx_msg) {
-	(*cb->on_rx_msg)(dlg, event->obj.tsx, event->src.rdata);
-    }
-
-    /* Now trigger high level events. 
-     * High level event should only occurs when dialog's state has changed,
-     * except for on_provisional, which may be called multiple times whenever
-     * response message is sent
-     */
-    if (dlg->state == PJSIP_DIALOG_STATE_PROCEEDING &&
-	(event->type== PJSIP_EVENT_TSX_STATE_CHANGED) && 
-	event->obj.tsx == dlg->invite_tsx) 
-    {
-	/* Sent/received provisional responses. */
-	if (cb->on_provisional)
-	    (*cb->on_provisional)(dlg, event->obj.tsx, event);
-    }
-
-    if (dlg_event == PJSIP_DIALOG_EVENT_MID_CALL_REQUEST) {
-	if (cb->on_mid_call_events)
-	    (*cb->on_mid_call_events)(dlg, event);
-	return;
-    }
-
-    if (dlg_event != PJSIP_DIALOG_EVENT_STATE_CHANGED)
-	return;
-
-    if (dlg->state == PJSIP_DIALOG_STATE_INCOMING) {
-
-	/* New incoming dialog. */
-	pj_assert (event->src_type == PJSIP_EVENT_RX_MSG);
-	(*cb->on_incoming)(dlg, event->obj.tsx, event->src.rdata);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_CALLING) {
-
-	/* Dialog has just sent the first INVITE. */
-	if (cb->on_calling) {
-	    (*cb->on_calling)(dlg, event->obj.tsx, event->src.tdata);
-	}
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_DISCONNECTED) {
-
-	if (cb->on_disconnected)
-	    (*cb->on_disconnected)(dlg, event);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_TERMINATED) {
-
-	if (cb->on_terminated)
-	    (*cb->on_terminated)(dlg);
-
-	pjsip_ua_destroy_dialog(dlg);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_CONNECTING) {
-
-	if (cb->on_connecting)
-	    (*cb->on_connecting)(dlg, event);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
-
-	if (cb->on_established)
-	    (*cb->on_established)(dlg, event);
-    }
-}
-
-/*
- * This callback receives event from the transaction layer (via User Agent),
- * or from dialog timer (for 200/INVITE or ACK retransmission).
- */
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 
-			     pjsip_transaction *tsx, 
-			     pjsip_event *event)
-{
-    int status = 0;
-    struct dialog_lock_data lck;
-
-    PJ_LOG(4, (dlg->obj_name, "state=%s (evt=%s, src=%s)", 
-			 pjsip_dlg_state_str(dlg->state),
-			 pjsip_event_str(event->type),
-			 pjsip_event_str(event->src_type)));
-
-
-    lock_dialog(dlg, &lck);
-
-    status = dlg_on_all_state_pre( dlg, tsx, event);
-
-    if (status==0) {
-	status = (*dlg->handle_tsx_event)(dlg, tsx, event);
-    }
-    if (status==0) {
-	status = dlg_on_all_state_post( dlg, tsx, event);
-    }
-    
-    unlock_dialog(dlg, &lck);
-}
-
-/*
- * This function contains common processing in all states, and it is called
- * before the FSM is invoked.
- */
-static int  dlg_on_all_state_pre( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event)
-
-    if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED)
-	return 0;
-
-    if (tsx && (tsx->state==PJSIP_TSX_STATE_CALLING || 
-	tsx->state==PJSIP_TSX_STATE_TRYING)) 
-    {
-	++dlg->pending_tsx_count;
-
-    } else if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) 
-    {
-	--dlg->pending_tsx_count;
-	if (tsx == dlg->invite_tsx)
-	    dlg->invite_tsx = NULL;
-    }
-
-    if (tsx->method.id == PJSIP_INVITE_METHOD) {
-	tsx->handle_ack = 1;
-    }
-    return 0;
-}
-
-
-/*
- * This function contains common processing in all states, and it is called
- * after the FSM is invoked.
- */
-static int  dlg_on_all_state_post( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event)
-
-    if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) {
-	if (dlg->pending_tsx_count == 0 &&
-	    dlg->state != PJSIP_DIALOG_STATE_CONNECTING &&
-	    dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED &&
-	    dlg->state != PJSIP_DIALOG_STATE_TERMINATED) 
-	{
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    return -1;
-	}
-    }
-
-    return 0;
-}
-
-
-/*
- * Internal function to initialize dialog, contains common initialization
- * for both UAS and UAC dialog.
- */
-static pj_status_t dlg_init( pjsip_dlg *dlg )
-{
-    /* Init mutex. */
-    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
-    if (!dlg->mutex) {
-	PJ_PERROR((dlg->obj_name, "pj_mutex_create()"));
-	return -1;
-    }
-
-    /* Init route-set (Initially empty) */
-    pj_list_init(&dlg->route_set);
-
-    /* Init auth credential list. */
-    pj_list_init(&dlg->auth_sess);
-
-    return PJ_SUCCESS;
-}
-
-/*
- * This one is called just before dialog is destroyed.
- * It is called while mutex is held.
- */
-PJ_DEF(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg )
-{
-    struct dialog_lock_data *lck;
-
-    //PJ_TODO(CHECK_THIS);
-    pj_assert(dlg->pending_tsx_count == 0);
-
-    /* Mark dialog as dead. */
-    lck = pj_thread_local_get(pjsip_dlg_lock_tls_id);
-    while (lck) {
-	if (lck->dlg == dlg)
-	    lck->is_alive = 0;
-	lck = lck->prev;
-    }
-}
-
-/*
- * Initialize dialog from the received request.
- * This is an internal function which is called by the User Agent (sip_ua.c), 
- * and it will initialize most of dialog's properties with values from the
- * received message.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg, pjsip_rx_data *rdata )
-{
-    pjsip_msg *msg = rdata->msg;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_name_addr *name_addr;
-    pjsip_sip_uri *url;
-    unsigned flag;
-    pjsip_event event;
-
-    pj_assert(dlg && rdata);
-
-    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p)", rdata));
-
-    /* Must be an INVITE request. */
-    pj_assert(msg->type == PJSIP_REQUEST_MSG && 
-	      msg->line.req.method.id == PJSIP_INVITE_METHOD);
-
-    /* Init general dialog data. */
-    if (dlg_init(dlg) != PJ_SUCCESS) {
-	return -1;
-    }
-
-    /* Get the To header. */
-    to = rdata->to;
-
-    /* Copy URI in the To header as our local URI. */
-    dlg->local.info = pjsip_hdr_clone( dlg->pool, to);
-
-    /* Set tag in the local info. */
-    dlg->local.info->tag = dlg->local.tag;
-
-    /* Create local Contact to be advertised in the response.
-     * At the moment, just copy URI from the local URI as our contact.
-     */
-    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
-    dlg->local.contact->star = 0;
-    name_addr = (pjsip_name_addr *)dlg->local.info->uri;
-    dlg->local.contact->uri = (pjsip_uri*) name_addr;
-    url = (pjsip_sip_uri*) name_addr->uri;
-    //url->port = rdata->via->sent_by.port;
-    //url->port = pj_sockaddr_get_port( pjsip_transport_get_local_addr(rdata->transport) );
-
-    /* Save remote URI. */
-    dlg->remote.info = pjsip_hdr_clone( dlg->pool, rdata->from );
-    pjsip_fromto_set_to( dlg->remote.info );
-    pj_strdup( dlg->pool, &dlg->remote.tag, &rdata->from->tag );
-
-    /* Save remote Contact. */
-    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-    if (contact) {
-    	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
-    } else {
-	PJ_LOG(3,(dlg->obj_name, "No Contact header in INVITE from %s", 
-		  pj_sockaddr_get_str_addr(&rdata->addr)));
-   	dlg->remote.contact = pjsip_contact_hdr_create( dlg->pool );
-	dlg->remote.contact->uri = dlg->remote.info->uri;
-    }
-
-    /* Save Call-ID. */
-    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
-    pj_strdup( dlg->pool, &dlg->call_id->id, &rdata->call_id );
-
-    /* Initialize local CSeq and save remote CSeq.*/
-    dlg->local.cseq = rdata->timestamp.sec & 0xFFFF;
-    dlg->remote.cseq = rdata->cseq->cseq;
-
-    /* Secure? */
-    flag = pjsip_transport_get_flag(rdata->transport);
-    dlg->secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
-
-    /* Initial state is NULL. */
-    event.type = event.src_type = PJSIP_EVENT_RX_MSG;
-    event.src.rdata = rdata;
-    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
-    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p) complete",  rdata));
-    return PJ_SUCCESS;
-}
-
-/*
- * Set the contact details.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
-					   const pj_str_t *contact )
-{
-    pjsip_uri *local_uri;
-    pj_str_t tmp;
-
-    pj_strdup_with_null(dlg->pool, &tmp, contact);
-    local_uri = pjsip_parse_uri( dlg->pool, tmp.ptr, tmp.slen, 
-				 PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (local_uri == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "set_contact: invalid URI"));
-	return -1;
-    }
-
-    dlg->local.contact->star = 0;
-    dlg->local.contact->uri = local_uri;
-    return 0;
-}
-
-/*
- * Set route set.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
-					     const pjsip_route_hdr *route_set )
-{
-    pjsip_route_hdr *hdr;
-
-    pj_list_init(&dlg->route_set);
-    hdr = route_set->next;
-    while (hdr != route_set) {
-	pjsip_route_hdr *cloned = pjsip_hdr_clone(dlg->pool, hdr);
-	pj_list_insert_before( &dlg->route_set, cloned);
-	hdr = hdr->next;
-    }
-    return 0;
-}
-
-/*
- * Set route set without cloning the header.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
-						pjsip_route_hdr *route_set)
-{
-    pjsip_route_hdr *hdr;
-
-    pj_list_init(&dlg->route_set);
-    hdr = route_set->next;
-    while (hdr != route_set) {
-	pj_list_insert_before( &dlg->route_set, hdr);
-	hdr = hdr->next;
-    }
-    return 0;
-}
-
-/*
- * Application calls this function when it wants to initiate an outgoing
- * dialog (incoming dialogs are created automatically by UA when it receives
- * INVITE, by calling pjsip_dlg_init_from_rdata()).
- * This function should initialize most of the dialog's properties.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
-				    const pj_str_t *c_local_info,
-				    const pj_str_t *c_remote_info,
-				    const pj_str_t *c_target)
-{
-    pj_time_val tv;
-    pjsip_event event;
-    pj_str_t buf;
-
-    if (!dlg || !c_local_info || !c_remote_info) {
-	pj_assert(dlg && c_local_info && c_remote_info);
-	return -1;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "initializing"));
-
-    /* Init general dialog */
-    if (dlg_init(dlg) != PJ_SUCCESS) {
-	return -1;
-    }
-
-    /* Duplicate local info. */
-    pj_strdup_with_null( dlg->pool, &buf, c_local_info);
-
-    /* Build local URI. */
-    dlg->local.target = pjsip_parse_uri(dlg->pool, buf.ptr, buf.slen, 
-				        PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (dlg->local.target == NULL) {
-	PJ_LOG(2, (dlg->obj_name, 
-		   "pjsip_dlg_init: invalid local URI %s", buf.ptr));
-	return -1;
-    }
-
-    /* Set local URI. */
-    dlg->local.info = pjsip_from_hdr_create(dlg->pool);
-    dlg->local.info->uri = dlg->local.target;
-    dlg->local.info->tag = dlg->local.tag;
-
-    /* Create local Contact to be advertised in the response. */
-    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
-    dlg->local.contact->star = 0;
-    dlg->local.contact->uri = dlg->local.target;
-
-    /* Set remote URI. */
-    dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
-
-    /* Duplicate to buffer. */
-    pj_strdup_with_null( dlg->pool, &buf, c_remote_info);
-
-    /* Build remote info. */
-    dlg->remote.info->uri = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen,
-					     PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (dlg->remote.info->uri == NULL) {
-	PJ_LOG(2, (dlg->obj_name, 
-		   "pjsip_dlg_init: invalid remote URI %s", buf.ptr));
-	return -1;
-    }
-
-    /* Set remote Contact initially equal to the remote URI. */
-    dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
-    dlg->remote.contact->star = 0;
-    dlg->remote.contact->uri = dlg->remote.info->uri;
-
-    /* Set initial remote target. */
-    if (c_target != NULL) {
-	pj_strdup_with_null( dlg->pool, &buf, c_target);
-	dlg->remote.target = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen, 0);
-	if (dlg->remote.target == NULL) {
-	    PJ_LOG(2, (dlg->obj_name, 
-		       "pjsip_dlg_init: invalid remote target %s", buf.ptr));
-	    return -1;
-	}
-    } else {
-	dlg->remote.target = dlg->remote.info->uri;
-    }
-
-    /* Create globally unique Call-ID */
-    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
-    pj_create_unique_string( dlg->pool, &dlg->call_id->id );
-
-    /* Local and remote CSeq */
-    pj_gettimeofday(&tv);
-    dlg->local.cseq = tv.sec & 0xFFFF;
-    dlg->remote.cseq = 0;
-
-    /* Initial state is NULL. */
-    event.type = event.src_type = PJSIP_EVENT_TX_MSG;
-    event.src.data = NULL;
-    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
-    /* Done. */
-    PJ_LOG(4, (dlg->obj_name, "%s dialog initialized, From: %.*s, To: %.*s",
-	       pjsip_role_name(dlg->role), 
-	       c_local_info->slen, c_local_info->ptr,
-	       c_remote_info->slen, c_remote_info->ptr));
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Set credentials.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_credentials(  pjsip_dlg *dlg,
-					        int count,
-						const pjsip_cred_info *cred)
-{
-    if (count > 0) {
-	dlg->cred_info = pj_pool_alloc(dlg->pool, count * sizeof(pjsip_cred_info));
-	pj_memcpy(dlg->cred_info, cred, count * sizeof(pjsip_cred_info));
-    }
-    dlg->cred_count = count;
-    return 0;
-}
-
-/*
- * Create a new request within dialog (i.e. after the dialog session has been
- * established). The construction of such requests follows the rule in 
- * RFC3261 section 12.2.1.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
-				      pjsip_dlg *dlg,
-				      const pjsip_method *method,
-				      int cseq )
-{
-    pjsip_tx_data *tdata;
-    pjsip_contact_hdr *contact;
-    pjsip_route_hdr *route, *end_list;
-
-    /* Contact Header field.
-     * Contact can only be present in requests that establish dialog (in the 
-     * core SIP spec, only INVITE).
-     */
-    if (method->id == PJSIP_INVITE_METHOD)
-	contact = dlg->local.contact;
-    else
-	contact = NULL;
-
-    tdata = pjsip_endpt_create_request_from_hdr( dlg->ua->endpt,
-						 method,
-						 dlg->remote.target,
-						 dlg->local.info,
-						 dlg->remote.info,
-						 contact,
-						 dlg->call_id,
-						 cseq,
-						 NULL);
-    if (!tdata) {
-	PJ_THROW(1);
-	return;
-    }
-
-    /* Just copy dialog route-set to Route header. 
-     * The transaction will do the processing as specified in Section 12.2.1
-     * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
-     */
-    route = dlg->route_set.next;
-    end_list = &dlg->route_set;
-    for (; route != end_list; route = route->next ) {
-	pjsip_route_hdr *r;
-	r = pjsip_hdr_shallow_clone( tdata->pool, route );
-	pjsip_routing_hdr_set_route(r);
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
-    }
-
-    /* Copy authorization headers. */
-    pjsip_auth_init_req( dlg->pool, tdata, &dlg->auth_sess,
-			 dlg->cred_count, dlg->cred_info);
-
-    *p_tdata = tdata;
-}
-
-
-/*
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
-						 const pjsip_method *method,
-						 int cseq)
-{
-    PJ_USE_EXCEPTION;
-    struct dialog_lock_data lck;
-    pjsip_tx_data *tdata = NULL;
-
-    pj_assert(dlg != NULL && method != NULL);
-    if (!dlg || !method) {
-	return NULL;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "Creating request"));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Use outgoing CSeq and increment it by one. */
-    if (cseq < 0)
-	cseq = dlg->local.cseq + 1;
-
-    PJ_LOG(5, (dlg->obj_name, "creating request %.*s cseq=%d", 
-			      method->name.slen, method->name.ptr, cseq));
-
-    /* Create the request. */
-    PJ_TRY {
-	dlg_create_request_throw(&tdata, dlg, method, cseq);
-	PJ_LOG(5, (dlg->obj_name, "request data %s created", tdata->obj_name));
-    }
-    PJ_CATCH_ANY {
-	/* Failed! Delete transmit data. */
-	if (tdata) {
-	    pjsip_tx_data_dec_ref( tdata );
-	    tdata = NULL;
-	}
-    }
-    PJ_END;
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * Sends request.
- * Select the transport for the request message
- */
-static pj_status_t dlg_send_request( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
-    pjsip_transaction *tsx;
-    pj_status_t status = PJ_SUCCESS;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL && tdata != NULL);
-    if (!dlg || !tdata) {
-	return -1;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "sending request %s", tdata->obj_name));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Create a new transaction. */
-    tsx = pjsip_endpt_create_tsx( dlg->ua->endpt );
-    if (!tsx) {
-	unlock_dialog(dlg, &lck);
-	return -1;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "Created new UAC transaction: %s", tsx->obj_name));
-
-    /* Initialize transaction */
-    tsx->module_data[dlg->ua->mod_id] = dlg;
-    status = pjsip_tsx_init_uac( tsx, tdata );
-    if (status != PJ_SUCCESS) {
-	unlock_dialog(dlg, &lck);
-	pjsip_endpt_destroy_tsx( dlg->ua->endpt, tsx );
-	return -1;
-    }
-    pjsip_endpt_register_tsx( dlg->ua->endpt, tsx );
-
-    /* Start the transaction. */
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return status;
-}
-
-/*
- * This function can be called by application to send ANY outgoing message
- * to remote party. 
- */
-PJ_DEF(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
-    pj_status_t status;
-    int tsx_status;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL && tdata != NULL);
-    if (!dlg || !tdata) {
-	return -1;
-    }
-
-    lock_dialog(dlg, &lck);
-
-    if (tdata->msg->type == PJSIP_REQUEST_MSG) {
-	int request_cseq;
-	pjsip_msg *msg = tdata->msg;
-	pjsip_cseq_hdr *cseq_hdr;
-
-	switch (msg->line.req.method.id) {
-	case PJSIP_CANCEL_METHOD:
-
-	    /* Check the INVITE transaction state. */
-	    tsx_status = dlg->invite_tsx->status_code;
-	    if (tsx_status >= 200) {
-		/* Already terminated. Can't cancel. */
-		status = -1;
-		goto on_return;
-	    }
-
-	    /* If we've got provisional response, then send CANCEL and wait for
-	     * the response to INVITE to arrive. Otherwise just send CANCEL and
-	     * terminate the INVITE.
-	     */
-	    if (tsx_status < 100) {
-		pjsip_tsx_terminate( dlg->invite_tsx, 
-				     PJSIP_SC_REQUEST_TERMINATED);
-		status = 0;
-		goto on_return;
-	    }
-
-	    status = 0;
-	    request_cseq = dlg->invite_tsx->cseq;
-	    break;
-
-	case PJSIP_ACK_METHOD:
-	    /* Sending ACK outside of transaction is not supported at present! */
-	    pj_assert(0);
-	    status = 0;
-	    request_cseq = dlg->local.cseq;
-	    break;
-
-	case PJSIP_INVITE_METHOD:
-	    /* For an initial INVITE, reset dialog state to NULL so we get
-	     * 'normal' UAC notifications such as on_provisional(), etc.
-	     * Initial INVITE is the request that is sent when the dialog has
-	     * not been established yet. It's not necessarily the first INVITE
-	     * sent, as when the Authorization fails, subsequent INVITE are also
-	     * considered as an initial INVITE.
-	     */
-	    if (dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
-		/* Set state to NULL. */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, NULL);
-
-	    } else {
-		/* This is a re-INVITE */
-	    }
-	    status = 0;
-	    request_cseq = dlg->local.cseq + 1;
-	    break;
-
-	default:
-	    status = 0;
-	    request_cseq = dlg->local.cseq + 1;
-	    break;
-	}
-
-	if (status != 0)
-	    goto on_return;
-
-	/* Update dialog's local CSeq, if necessary. */
-	if (request_cseq != dlg->local.cseq)
-	    dlg->local.cseq = request_cseq;
-
-	/* Update CSeq header in the request. */
-	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
-							 PJSIP_H_CSEQ, NULL);
-	pj_assert(cseq_hdr != NULL);
-
-	/* Update the CSeq */
-	cseq_hdr->cseq = request_cseq;
-
-	/* Force the whole message to be re-printed. */
-	pjsip_tx_data_invalidate_msg( tdata );
-
-	/* Now send the request. */
-	status = dlg_send_request(dlg, tdata);
-
-    } else {
-	/*
-	 * This is only valid for sending response to INVITE!
-	 */
-	pjsip_cseq_hdr *cseq_hdr;
-
-	if (dlg->invite_tsx == NULL || dlg->invite_tsx->status_code >= 200) {
-	    status = -1;
-	    goto on_return;
-	}
-
-	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
-							 PJSIP_H_CSEQ, NULL);
-	pj_assert(cseq_hdr);
-
-	if (cseq_hdr->method.id != PJSIP_INVITE_METHOD) {
-	    status = -1;
-	    goto on_return;
-	}
-
-	pj_assert(cseq_hdr->cseq == dlg->invite_tsx->cseq);
-	
-	pjsip_tsx_on_tx_msg(dlg->invite_tsx, tdata);
-	status = 0;
-    }
-
-on_return:
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-   
-    /* Whatever happen delete the message. */
-    pjsip_tx_data_dec_ref( tdata );
-
-    return status;
-}
-
-/*
- * Sends outgoing invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg )
-{
-    pjsip_method method;
-    struct dialog_lock_data lck;
-    const pjsip_allow_hdr *allow_hdr;
-    pjsip_tx_data *tdata;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to send invitation"));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Create request. */
-    pjsip_method_set( &method, PJSIP_INVITE_METHOD);
-    tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-    if (tdata == NULL) {
-	unlock_dialog(dlg, &lck);
-	return NULL;
-    }
-
-    /* Invite SHOULD contain "Allow" header. */
-    allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
-    if (allow_hdr) {
-	pjsip_msg_add_hdr( tdata->msg, 
-			   pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
-    }
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * Cancel pending outgoing dialog invitation. 
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg )
-{
-    pjsip_tx_data *tdata = NULL;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to cancel invitation"));
-
-    lock_dialog(dlg, &lck);
-
-    /* Check the INVITE transaction. */
-    if (dlg->invite_tsx == NULL || dlg->role != PJSIP_ROLE_UAC) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
-				  "no INVITE transaction found"));
-	goto on_return;
-    }
-
-    /* Construct the CANCEL request. */
-    tdata = pjsip_endpt_create_cancel( dlg->ua->endpt,
-				       dlg->invite_tsx->last_tx );
-    if (tdata == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
-				  "unable to construct request"));
-	goto on_return;
-    }
-
-    /* Add reference counter to tdata. */
-    pjsip_tx_data_add_ref(tdata);
-
-on_return:
-    unlock_dialog(dlg, &lck);
-    return tdata;
-}
-
-
-/*
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )
-{
-    pjsip_tx_data *tdata = NULL;
-    pjsip_msg *msg;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "pjsip_dlg_answer: code=%d", code));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Must have pending INVITE. */
-    if (dlg->invite_tsx == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: no INVITE transaction found"));
-	goto on_return;
-    }
-    /* Must be UAS. */
-    if (dlg->role != PJSIP_ROLE_UAS) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: not UAS"));
-	goto on_return;
-    }
-    /* Must have not answered with final response before. */
-    if (dlg->invite_tsx->status_code >= 200) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: transaction already terminated "
-				  "with status %d", dlg->invite_tsx->status_code));
-	goto on_return;
-    }
-
-    /* Get transmit data and the message. 
-     * We will rewrite the message with a new status code.
-     */
-    only if tdata is not pending!!!
-    tdata = dlg->invite_tsx->last_tx;
-    msg = tdata->msg;
-
-    /* Set status code and reason phrase. */
-    if (code < 100 || code >= 700) code = 500;
-    msg->line.status.code = code;
-    msg->line.status.reason = *pjsip_get_status_text(code);
-
-    /* For 2xx response, Contact and Record-Route must be added. */
-    if (PJSIP_IS_STATUS_IN_CLASS(code,200)) {
-	const pjsip_allow_hdr *allow_hdr;
-
-	if (pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL) == NULL) {
-	    pjsip_contact_hdr *contact;
-	    contact = pjsip_hdr_shallow_clone( tdata->pool, dlg->local.contact);
-	    pjsip_msg_add_hdr( msg, (pjsip_hdr*)contact );
-	}
-
-	/* 2xx response MUST contain "Allow" header. */
-	allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
-	if (allow_hdr) {
-	    pjsip_msg_add_hdr( msg, pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
-	}
-    }
-
-    /* for all but 100 responses, To-tag must be set. */
-    if (code != 100) {
-	pjsip_to_hdr *to;
-	to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL);
-	to->tag = dlg->local.tag;
-    }
-
-    /* Reset packet buffer. */
-    pjsip_tx_data_invalidate_msg(tdata);
-
-    /* Add reference counter */
-    pjsip_tx_data_add_ref(tdata);
-
-on_return:
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-
-/*
- * Send BYE request to terminate the dialog's session.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg )
-{
-    pjsip_method method;
-    struct dialog_lock_data lck;
-    pjsip_tx_data *tdata;
-
-    if (!dlg) {
-	pj_assert(dlg != NULL);
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to terminate session"));
-
-    lock_dialog(dlg, &lck);
-
-    pjsip_method_set( &method, PJSIP_BYE_METHOD);
-    tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * High level function to disconnect dialog's session. Depending on dialog's 
- * state, this function will either send CANCEL, final response, or BYE to
- * trigger the disconnection. A status code must be supplied, which will be
- * sent if dialog will be transmitting a final response to INVITE.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, 
-					     int status_code )
-{
-    pjsip_tx_data *tdata = NULL;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    switch (dlg->state) {
-    case PJSIP_DIALOG_STATE_INCOMING:
-	tdata = pjsip_dlg_answer(dlg, status_code);
-	break;
-
-    case PJSIP_DIALOG_STATE_CALLING:
-	tdata = pjsip_dlg_cancel(dlg);
-	break;
-
-    case PJSIP_DIALOG_STATE_PROCEEDING:
-	if (dlg->role == PJSIP_ROLE_UAC) {
-	    tdata = pjsip_dlg_cancel(dlg);
-	} else {
-	    tdata = pjsip_dlg_answer(dlg, status_code);
-	}
-	break;
-
-    case PJSIP_DIALOG_STATE_ESTABLISHED:
-	tdata = pjsip_dlg_bye(dlg);
-	break;
-
-    default:
-	PJ_LOG(4,(dlg->obj_name, "Invalid state %s in pjsip_dlg_disconnect()", 
-		  dlg_state_names[dlg->state]));
-	break;
-    }
-
-    return tdata;
-}
-
-/*
- * Handling of the receipt of 2xx/INVITE response.
- */
-static void dlg_on_recv_2xx_invite( pjsip_dlg *dlg,
-				    pjsip_event *event )
-{
-    pjsip_msg *msg;
-    pjsip_contact_hdr *contact;
-    pjsip_hdr *hdr, *end_hdr;
-    pjsip_method method;
-    pjsip_tx_data *ack_tdata;
-    
-    /* Get the message */
-    msg = event->src.rdata->msg;
-    
-    /* Update remote's tag information. */
-    pj_strdup(dlg->pool, &dlg->remote.info->tag, &event->src.rdata->to_tag);
-
-    /* Copy Contact information in the 2xx/INVITE response to dialog's.
-     * remote contact
-     */
-    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-    if (contact) {
-	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
-    } else {
-	/* duplicate contact from "From" header (?) */
-	PJ_LOG(4,(dlg->obj_name, "Received 200/OK to INVITE with no Contact!"));
-	dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
-	dlg->remote.contact->uri = dlg->remote.info->uri;
-    }
-    
-    /* Copy Record-Route header (in reverse order) as dialog's route-set,
-     * overwriting previous route-set, if any, even if the received route-set
-     * is empty.
-     */
-    pj_list_init(&dlg->route_set);
-    end_hdr = &msg->hdr;
-    for (hdr = msg->hdr.prev; hdr!=end_hdr; hdr = hdr->prev) {
-	if (hdr->type == PJSIP_H_RECORD_ROUTE) {
-	    pjsip_route_hdr *r;
-	    r = pjsip_hdr_clone(dlg->pool, hdr);
-	    pjsip_routing_hdr_set_route(r);
-	    pj_list_insert_before(&dlg->route_set, r);
-	}
-    }
-    
-    /* On receipt of 200/INVITE response, send ACK. 
-     * This ack must be saved and retransmitted whenever we receive
-     * 200/INVITE retransmission, until 64*T1 seconds elapsed.
-     */
-    pjsip_method_set( &method, PJSIP_ACK_METHOD);
-    ack_tdata = pjsip_dlg_create_request( dlg, &method, dlg->invite_tsx->cseq);
-    if (ack_tdata == NULL) {
-	//PJ_TODO(HANDLE_CREATE_ACK_FAILURE)
-	PJ_LOG(2, (dlg->obj_name, "Error sending ACK msg: can't create request"));
-	return;
-    }	
-    
-    /* Send with the transaction. */
-    pjsip_tsx_on_tx_ack( dlg->invite_tsx, ack_tdata);
-	
-    /* Decrement reference counter because pjsip_dlg_create_request 
-     * automatically increments the request.
-     */
-    pjsip_tx_data_dec_ref( ack_tdata );
-}
-
-/*
- * State NULL, before any events have been received.
- */
-static int  dlg_on_state_null( pjsip_dlg *dlg, 
-			       pjsip_transaction *tsx,
-			       pjsip_event *event)
-{
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_RX_MSG) 
-    {
-	pjsip_hdr *hdr, *hdr_list;
-
-	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
-	/* Save the INVITE transaction. */
-	dlg->invite_tsx = tsx;
-
-	/* Change state to INCOMING */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_INCOMING, event);
-
-	/* Create response buffer. */
-	tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 100);
-	pjsip_tx_data_add_ref(tsx->last_tx);
-
-	/* Copy the Record-Route headers into dialog's route_set, maintaining
-	 * the order.
-	 */
-	pj_list_init(&dlg->route_set);
-	hdr_list = &event->src.rdata->msg->hdr;
-	hdr = hdr_list->next;
-	while (hdr != hdr_list) {
-	    if (hdr->type == PJSIP_H_RECORD_ROUTE) {
-		pjsip_route_hdr *route;
-		route = pjsip_hdr_clone(dlg->pool, hdr);
-		pjsip_routing_hdr_set_route(route);
-		pj_list_insert_before(&dlg->route_set, route);
-	    }
-	    hdr = hdr->next;
-	}
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	       event->src_type == PJSIP_EVENT_TX_MSG) 
-    {
-	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
-	/* Save the INVITE transaction. */
-	dlg->invite_tsx = tsx;
-
-	/* Change state to CALLING. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_CALLING, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-/*
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
-static int  dlg_on_state_incoming( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event)
-{
-    return dlg_on_state_proceeding_callee( dlg, tsx, event );
-}
-
-/*
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
-static int  dlg_on_state_calling( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event)
-{
-    if (tsx == dlg->invite_tsx) {
-	return dlg_on_state_proceeding_caller( dlg, tsx, event );
-    }
-    return 0;
-}
-
-/*
- * State PROCEEDING is after provisional response is received.
- * Since the processing is similar to state CALLING, this function is also
- * called for CALLING state.
- */
-static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event)
-{
-    int dlg_is_terminated = 0;
-
-    /* We only care about our INVITE transaction. 
-     * Ignore other transaction progression (such as CANCEL).
-     */
-    if (tsx != dlg->invite_tsx) {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	return 0;
-    }
-
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED) {
-	switch (tsx->state) {
-	case PJSIP_TSX_STATE_PROCEEDING:
-	    if (dlg->state != PJSIP_DIALOG_STATE_PROCEEDING) {
-		/* Change state to PROCEEDING */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
-		/* Notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    } else {
-		/* Also notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	    }
-	    break;
-
-	case PJSIP_TSX_STATE_COMPLETED:
-	    /* Change dialog state. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		/* Update remote target, take it from the contact hdr. */
-		pjsip_contact_hdr *contact;
-		contact = pjsip_msg_find_hdr(event->src.rdata->msg, 
-					     PJSIP_H_CONTACT, NULL);
-		if (contact) {
-		    dlg->remote.target = pjsip_uri_clone(dlg->pool, contact->uri);
-		} else {
-		    PJ_LOG(4,(dlg->obj_name, 
-			      "Warning: found no Contact hdr in 200/OK"));
-		}
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
-	    } else if (tsx->status_code==401 || tsx->status_code==407) {
-		/* Handle Authentication challenge. */
-		pjsip_tx_data *tdata;
-		tdata = pjsip_auth_reinit_req( dlg->ua->endpt,
-					       dlg->pool, &dlg->auth_sess,
-					       dlg->cred_count, dlg->cred_info,
-					       tsx->last_tx, event->src.rdata);
-		if (tdata) {
-		    /* Re-use original request, with a new transaction. 
-		     * Need not to worry about CSeq, dialog will take care.
-		     */
-		    pjsip_dlg_send_msg(dlg, tdata);
-		    return 0;
-		} else {
-		    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-		}
-	    } else {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* Send ACK when dialog is connected. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		pj_assert(event->src_type == PJSIP_EVENT_RX_MSG);
-		dlg_on_recv_2xx_invite(dlg, event);
-	    }
-	    break;
-
-	case PJSIP_TSX_STATE_TERMINATED:
-	    /*
-	     * Transaction is terminated because of timeout or transport error.
-	     * To let the application go to normal state progression, call the
-	     * callback twice. First is to emulate disconnection, and then call
-	     * again (with state TERMINATED) to destroy the dialog.
-	     */
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* The INVITE transaction will be destroyed, so release reference 
-	     * to it. 
-	     */
-	    dlg->invite_tsx = NULL;
-
-	    /* We should terminate the dialog now.
-	     * But it's possible that we have other pending transactions (for 
-	     * example, outgoing CANCEL is in progress).
-	     * So destroy the dialog only if there's no other transaction.
-	     */
-	    if (dlg->pending_tsx_count == 0) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-		dlg_is_terminated = 1;
-	    }
-	    break;
-
-	default:
-	    pj_assert(0);
-	    break;
-	}
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-    return dlg_is_terminated ? -1 : 0;
-}
-
-/*
- * State PROCEEDING for UAS is after the callee send provisional response.
- * This function is also called for INCOMING state.
- */
-static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event)
-{
-    int dlg_is_terminated = 0;
-
-    pj_assert( dlg->invite_tsx != NULL );
-
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_TX_MSG && 
-	tsx == dlg->invite_tsx) 
-    {
-	switch (tsx->state) {
-	case PJSIP_TSX_STATE_PROCEEDING:
-	    /* Change state to PROCEEDING */
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    break;
-
-	case PJSIP_TSX_STATE_COMPLETED:
-	case PJSIP_TSX_STATE_TERMINATED:
-	    /* Change dialog state. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
-	    } else {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* If transaction is terminated in non-2xx situation, 
-	     * terminate dialog as well. This happens when something unexpected
-	     * occurs, such as transport error.
-	     */
-	    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
-		!PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) 
-	    {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-		dlg_is_terminated = 1;
-	    }
-	    break;
-
-	default:
-	    pj_assert(0);
-	    break;
-	}
-
-    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	       event->src_type == PJSIP_EVENT_RX_MSG && 
-	       tsx->method.id == PJSIP_CANCEL_METHOD) 
-    {
-	pjsip_tx_data *tdata;
-
-	/* Check if sequence number matches the pending INVITE. */
-	if (dlg->invite_tsx==NULL ||
-	    pj_strcmp(&tsx->branch, &dlg->invite_tsx->branch) != 0) 
-	{
-	    PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no matching INVITE"));
-
-	    /* No matching INVITE transaction found. */
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						PJSIP_SC_CALL_TSX_DOES_NOT_EXIST );
-	    pjsip_tsx_on_tx_msg(tsx, tdata);
-	    return 0;
-	}
-
-	/* Always respond the CANCEL with 200/CANCEL no matter what. */
-	tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-					    event->src.rdata,
-					    200 );
-	pjsip_tsx_on_tx_msg( tsx, tdata );
-
-	/* Respond the INVITE transaction with 487, only if transaction has
-	 * not completed. 
-	 */
-	if (dlg->invite_tsx->last_tx) {
-	    if (dlg->invite_tsx->status_code < 200) {
-		tdata = dlg->invite_tsx->last_tx;
-		tdata->msg->line.status.code = 487;
-		tdata->msg->line.status.reason = *pjsip_get_status_text(487);
-		/* Reset packet buffer. */
-		pjsip_tx_data_invalidate_msg(tdata);
-		pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
-	    } else {
-		PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no effect, "
-					  "Transaction already terminated "
-					  "with status %d",
-					  dlg->invite_tsx->status_code));
-	    }
-	} else {
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						487);
-	    pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
-	}
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return dlg_is_terminated ? -1 : 0;
-}
-
-static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    if (dlg->role == PJSIP_ROLE_UAC) {
-	return dlg_on_state_proceeding_caller( dlg, tsx, event );
-    } else {
-	return dlg_on_state_proceeding_callee( dlg, tsx, event );
-    }
-}
-
-static int  dlg_on_state_connecting( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    if (tsx == dlg->invite_tsx) {
-	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	    (tsx->state == PJSIP_TSX_STATE_TERMINATED ||
-	    tsx->state == PJSIP_TSX_STATE_COMPLETED ||
-	    tsx->state == PJSIP_TSX_STATE_CONFIRMED)) 
-	{
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_ESTABLISHED, event);
-	    } else {
-		/* Probably because we never get the ACK, or transport error
-		* when sending ACK.
-		*/
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	} else {
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	}
-    } else {
-	/* Handle case when transaction is started when dialog is connecting
-	* (e.g. BYE requests cross wire.
-	*/
-	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	    event->src_type == PJSIP_EVENT_RX_MSG &&
-	    tsx->role == PJSIP_ROLE_UAS)
-	{
-	    pjsip_tx_data *response;
-
-	    if (tsx->status_code >= 200)
-		return 0;
-
-	    if (tsx->method.id == PJSIP_BYE_METHOD) {
-		/* Set state to DISCONNECTED. */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
-		/* Notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-		response = pjsip_endpt_create_response(	dlg->ua->endpt, 
-							event->src.rdata, 200);
-	    } else {
-		response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
-							PJSIP_SC_INTERNAL_SERVER_ERROR);
-	    }
-
-	    if (response)
-		pjsip_tsx_on_tx_msg(tsx, response);
-
-	    return 0;
-	}
-    }
-    return 0;
-}
-
-static int  dlg_on_state_established( pjsip_dlg *dlg, 
-				      pjsip_transaction *tsx,
-				      pjsip_event *event)
-{
-    PJ_UNUSED_ARG(tsx)
-
-    if (tsx && tsx->method.id == PJSIP_BYE_METHOD) {
-	/* Set state to DISCONNECTED. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	/* Answer with 200/BYE. */
-	if (event->src_type == PJSIP_EVENT_RX_MSG) {
-	    pjsip_tx_data *tdata;
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						200 );
-	    if (tdata)
-		pjsip_tsx_on_tx_msg( tsx, tdata );
-	}
-    } else if (tsx && event->src_type == PJSIP_EVENT_RX_MSG) {
-	pjsip_method_e method = event->src.rdata->cseq->method.id;
-
-	PJ_TODO(PROPERLY_HANDLE_REINVITATION)
-
-	/* Reinvitation. The message may be INVITE or an ACK. */
-	if (method == PJSIP_INVITE_METHOD) {
-	    if (dlg->invite_tsx && dlg->invite_tsx->status_code < 200) {
-		/* Section 14.2: A UAS that receives a second INVITE before it 
-		* sends the final response to a first INVITE with a lower
-		* CSeq sequence number on the same dialog MUST return a 500 
-		* (Server Internal Error) response to the second INVITE and 
-		* MUST include a Retry-After header field with a randomly 
-		* chosen value of between 0 and 10 seconds.
-		*/
-		pjsip_retry_after_hdr *hdr;
-		pjsip_tx_data *tdata = 
-		    pjsip_endpt_create_response(dlg->ua->endpt, 
-						event->src.rdata, 500);
-
-		if (!tdata)
-		    return 0;
-
-		/* Add Retry-After. */
-		hdr = pjsip_retry_after_hdr_create(tdata->pool);
-		hdr->ivalue = 9;
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
-
-		/* Send. */
-		pjsip_tsx_on_tx_msg(tsx, tdata);
-
-		return 0;
-	    }
-
-	    /* Keep this as our current INVITE transaction. */
-	    dlg->invite_tsx = tsx;
-
-	    /* Create response buffer. */
-	    tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, 
-							event->src.rdata, 100);
-	    pjsip_tx_data_add_ref(tsx->last_tx);
-
-	}
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_MID_CALL_REQUEST, event);
-
-    }  else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 
-				       pjsip_transaction *tsx,
-				       pjsip_event *event)
-{
-    PJ_UNUSED_ARG(tsx)
-
-    /* Handle case when transaction is started when dialog is disconnected
-     * (e.g. BYE requests cross wire.
-     */
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_RX_MSG &&
-	tsx->role == PJSIP_ROLE_UAS)
-    {
-	pjsip_tx_data *response = NULL;
-
-	if (tsx->status_code >= 200)
-	    return 0;
-
-	if (tsx->method.id == PJSIP_BYE_METHOD) {
-	    response = pjsip_endpt_create_response( dlg->ua->endpt, 
-						    event->src.rdata, 200);
-	} else {
-	    response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 
-						    PJSIP_SC_INTERNAL_SERVER_ERROR);
-	}
-	if (response)
-	    pjsip_tsx_on_tx_msg(tsx, response);
-
-	return 0;
-    } 
-    /* Handle case when outgoing BYE was rejected with 401/407 */
-    else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	     event->src_type == PJSIP_EVENT_RX_MSG &&
-	     tsx->role == PJSIP_ROLE_UAC)
-    {
-	if (tsx->status_code==401 || tsx->status_code==407) {
-	    pjsip_tx_data *tdata;
-	    tdata = pjsip_auth_reinit_req( dlg->ua->endpt, dlg->pool,
-					   &dlg->auth_sess,
-					   dlg->cred_count, dlg->cred_info,
-					   tsx->last_tx, event->src.rdata);
-	    if (tdata) {
-		pjsip_dlg_send_msg(dlg, tdata);
-	    }
-	}
-    }
-	    
-
-    if (dlg->pending_tsx_count == 0) {
-	/* Set state to TERMINATED. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	return -1;
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-static int  dlg_on_state_terminated( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    PJ_UNUSED_ARG(dlg)
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(event)
-
-    return -1;
-}
-
Index: project/trunk/pjsip/src/pjsip-ua/sip_ua.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_ua.c	(revision 126)
+++ 	(revision )
@@ -1,473 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_transaction.h>
-#include <pj/list.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/hash.h>
-#include <pj/pool.h>
-
-#define PJSIP_POOL_LEN_USER_AGENT   1024
-#define PJSIP_POOL_INC_USER_AGENT   0
-
-
-#define LOG_THIS    "useragent.."
-
-/*
- * Static prototypes.
- */
-static pj_status_t ua_load(pjsip_endpoint *endpt);
-static pj_status_t ua_unload(void);
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *evt );
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua,
-			       pjsip_rx_data *rdata );
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
-				       pj_str_t *key );
-PJ_DECL(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg );
-
-/*
- * Module interface.
- */
-static struct user_agent
-{
-    pjsip_module	 mod;
-    pj_pool_t		*pool;
-    pjsip_endpoint	*endpt;
-    pj_mutex_t		*mutex;
-    pj_hash_table_t	*dlg_table;
-    pjsip_dialog	 dlg_list;
-
-} mod_ua = 
-{
-  {
-    NULL, NULL,		    /* prev, next.			*/
-    { "mod-ua", 6 },	    /* Name.				*/
-    -1,			    /* Id				*/
-    PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,	/* Priority		*/
-    NULL,		    /* User data.			*/
-    0,			    /* Number of methods supported.	*/
-    { 0 },		    /* Array of methods			*/
-    &ua_load,		    /* load()				*/
-    NULL,		    /* start()				*/
-    NULL,		    /* stop()				*/
-    &ua_unload,		    /* unload()				*/
-    NULL,		    /* on_rx_request()			*/
-    NULL,		    /* on_rx_response()			*/
-    NULL,		    /* on_tx_request.			*/
-    NULL,		    /* on_tx_response()			*/
-    NULL,		    /* on_tsx_state()			*/
-  }
-};
-
-/*
- * Initialize user agent instance.
- */
-static pj_status_t ua_load( pjsip_endpoint *endpt )
-{
-    extern int pjsip_dlg_lock_tls_id;	/* defined in sip_dialog.c */
-    pj_status_t status;
-
-    /* Initialize the user agent. */
-    mod_ua.endpt = endpt;
-    status = pjsip_endpt_create_pool( endpt, "pua%p", PJSIP_POOL_LEN_UA, 
-				      PJSIP_POOL_INC_UA, &mod_ua.pool);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
-    if (ua->dlg_table == NULL)
-	return PJ_ENOMEM;
-
-    pj_list_init(&mod_ua.dlg_list);
-
-    /* Initialize dialog lock. */
-    pjsip_dlg_lock_tls_id = pj_thread_local_alloc();
-    if (pjsip_dlg_lock_tls_id == -1) {
-	return -1;
-    }
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Destroy user agent.
- */
-static pj_status_t ua_unload()
-{
-    pj_mutex_unlock(mod_ua.mutex);
-
-    /* Release pool */
-    if (mod_ua.pool) {
-	pjsip_endpt_destroy_pool( mod_ua.endpt, mod_ua.pool );
-    }
-    return PJ_SUCCESS;
-}
-
-/* 
- * Find dialog.
- * This function is called for a new transactions, which a dialog hasn't been
- * 'attached' to the transaction.
- */
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua, pjsip_rx_data *rdata )
-{
-    pjsip_dlg *dlg;
-    pj_str_t *tag;
-
-    /* Non-CANCEL requests/response can be found by looking at the tag in the
-     * hash table. CANCEL requests don't have tags, so instead we'll try to
-     * find the UAS INVITE transaction in endpoint's hash table
-     */
-    if (rdata->cseq->method.id == PJSIP_CANCEL_METHOD) {
-
-	/* Create key for the rdata, but this time, use INVITE as the
-	 * method.
-	 */
-	pj_str_t key;
-	pjsip_role_e role;
-	pjsip_method invite_method;
-	pjsip_transaction *invite_tsx;
-
-	if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	    role = PJSIP_ROLE_UAS;
-	} else {
-	    role = PJSIP_ROLE_UAC;
-	}
-	pjsip_method_set(&invite_method, PJSIP_INVITE_METHOD);
-	pjsip_tsx_create_key(rdata->pool, &key, role, &invite_method, rdata);
-
-	/* Lookup the INVITE transaction */
-	invite_tsx = pjsip_endpt_find_tsx(ua->endpt, &key);
-
-	/* We should find the dialog attached to the INVITE transaction */
-	return invite_tsx ? 
-	    (pjsip_dlg*) invite_tsx->module_data[ua->mod_id] : NULL;
-
-    } else {
-	if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	    tag = &rdata->to_tag;
-	} else {
-	    tag = &rdata->from_tag;
-	}
-	/* Find the dialog in UA hash table */
-	pj_mutex_lock(ua->mutex);
-	dlg = pj_hash_get( ua->dlg_table, tag->ptr, tag->slen );
-	pj_mutex_unlock(ua->mutex);
-    }
-    
-    return dlg;
-}
-
-/*
- * This function receives event notification from transactions. It is called by
- * endpoint.
- */
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_user_agent *ua = mod->mod_data;
-    pjsip_dlg *dlg = NULL;
-    pjsip_transaction *tsx = event->obj.tsx;
-
-    PJ_LOG(5, (LOG_THIS, "ua_tsx_handler(tsx=%s, evt=%s, src=%s, data=%p)", 
-	       (tsx ? tsx->obj_name : "NULL"),  pjsip_event_str(event->type), 
-	       pjsip_event_str(event->src_type), event->src.data));
-
-    /* Special case to handle ACK which doesn't match any INVITE transactions. */
-    if (event->type == PJSIP_EVENT_RX_ACK_MSG) {
-	/* Find the dialog based on the "tag". */
-	dlg = find_dialog( ua, event->src.rdata );
-
-	/* We should be able to find it. */
-	if (!dlg) {
-	    PJ_LOG(4,(LOG_THIS, "Unable to find dialog for incoming ACK"));
-	    return;
-	}
-
-	/* Match CSeq with pending INVITE in dialog. */
-	if (dlg->invite_tsx && dlg->invite_tsx->cseq==event->src.rdata->cseq->cseq) {
-	    /* A match found. */
-	    tsx = dlg->invite_tsx;
-
-	    /* Pass the event to transaction if transaction handles ACK. */
-	    if (tsx->handle_ack) {
-		PJ_LOG(4,(LOG_THIS, "Re-routing strandled ACK to transaction"));
-		pjsip_tsx_on_rx_msg(tsx, event->src.rdata);
-		return;
-	    }
-	} else {
-	    tsx = NULL;
-	    PJ_LOG(4,(LOG_THIS, "Unable to find INVITE tsx for incoming ACK"));
-	    return;
-	}
-    }
-
-    /* For discard event, transaction is NULL. */
-    if (tsx == NULL) {
-	return;
-    }
-
-    /* Try to pickup the dlg from the transaction. */
-    dlg = (pjsip_dlg*) tsx->module_data[ua->mod_id];
-
-    if (dlg != NULL) {
-
-	/* Nothing to do now. */
-
-    } else if (event->src_type == PJSIP_EVENT_RX_MSG)  {
-
-	/* This must be a new UAS transaction. */
-
-	/* Finds dlg that can handle this transaction. */
-	dlg = find_dialog( ua, event->src.rdata);
-
-	/* Create a new dlg if there's no existing dlg that can handle 
-	   the request, ONLY if the incoming message is an INVITE request.
-	 */
-	if (dlg==NULL && event->src.rdata->msg->type == PJSIP_REQUEST_MSG) {
-
-	    if (event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
-		/* Create new dialog. */
-		dlg = pjsip_ua_create_dialog( ua, PJSIP_ROLE_UAS );
-
-		if (dlg == NULL ||
-		    pjsip_dlg_init_from_rdata( dlg, event->src.rdata) != 0) 
-		{
-		    pjsip_tx_data *tdata;
-
-		    /* Dialog initialization has failed. Respond request with 500 */
-		    if (dlg) {
-			pjsip_ua_destroy_dialog(dlg);
-		    }
-		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 
-							PJSIP_SC_INTERNAL_SERVER_ERROR);
-		    if (tdata) {
-			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
-		    }
-		    return;
-		}
-
-	    } else {
-		pjsip_tx_data *tdata;
-
-		/* Check the method */
-		switch (tsx->method.id) {
-		case PJSIP_INVITE_METHOD:
-		case PJSIP_ACK_METHOD:
-		case PJSIP_BYE_METHOD:
-		case PJSIP_CANCEL_METHOD:
-		    /* Stale non-INVITE request.
-		     * For now, respond all stale requests with 481 (?).
-		     */
-		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 
-							PJSIP_SC_CALL_TSX_DOES_NOT_EXIST);
-		    if (tdata) {
-			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
-		    }
-		    break;
-		}
-
-		return;
-	    }
-	} else {
-	    /* Check the method */
-	    switch (tsx->method.id) {
-	    case PJSIP_INVITE_METHOD:
-	    case PJSIP_ACK_METHOD:
-	    case PJSIP_BYE_METHOD:
-	    case PJSIP_CANCEL_METHOD:
-		/* These methods belongs to dialog.
-		 * If we receive these methods while no dialog is found, 
-		 * then it must be a stale responses.
-		 */
-		break;
-	    default:
-		return;
-	    }
-
-	}
-	
-	if (dlg == NULL) {
-	    PJ_LOG(3, (LOG_THIS, "Receives spurious rdata %p from %s:%d",
-		       event->src.rdata, 
-		       pj_sockaddr_get_str_addr(&event->src.rdata->addr),
-		       pj_sockaddr_get_port(&event->src.rdata->addr)));
-	}
-
-	/* Set the dlg in the transaction (dlg can be NULL). */
-	tsx->module_data[ua->mod_id] = dlg;
-
-    } else {
-	/* This CAN happen with event->src_type == PJSIP_EVENT_TX_MSG
-	 * if UAS is responding to a transaction which does not exist. 
-	 * Just ignore.
-	 */
-	return;
-    }
-
-    /* Pass the event to the dlg. */
-    if (dlg) {
-	pjsip_dlg_on_tsx_event(dlg, tsx, event);
-    }
-}
-
-/*
- * Register dialog to UA.
- */
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
-				       pj_str_t *key )
-{
-    /* Assure that no entry with similar key exists in the hash table. */
-    pj_assert( pj_hash_get( ua->dlg_table, key->ptr, key->slen) == 0);
-
-    /* Insert entry to hash table. */
-    pj_hash_set( dlg->pool, ua->dlg_table, 
-		 key->ptr, key->slen, dlg);
-
-    /* Insert to the list. */
-    pj_list_insert_before(&ua->dlg_list, dlg);
-    return PJ_SUCCESS;
-}
-
-/*
- * Create a new dialog.
- */
-PJ_DEF(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,
-					      pjsip_role_e role )
-{
-    pj_pool_t *pool;
-    pjsip_dlg *dlg;
-
-    PJ_UNUSED_ARG(ua)
-
-    /* Create pool for the dialog. */
-    pool = pjsip_endpt_create_pool( ua->endpt, "pdlg%p",
-				    PJSIP_POOL_LEN_DIALOG,
-				    PJSIP_POOL_INC_DIALOG);
-
-    /* Create the dialog. */
-    dlg = pj_pool_calloc(pool, 1, sizeof(pjsip_dlg));
-    dlg->pool = pool;
-    dlg->ua = ua;
-    dlg->role = role;
-    sprintf(dlg->obj_name, "dlg%p", dlg);
-
-    /* Create mutex for the dialog. */
-    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
-    if (!dlg->mutex) {
-	pjsip_endpt_destroy_pool(ua->endpt, pool);
-	return NULL;
-    }
-
-    /* Create unique tag for the dialog. */
-    pj_create_unique_string( pool, &dlg->local.tag );
-
-    /* Register dialog. */
-    pj_mutex_lock(ua->mutex);
-    if (ua_register_dialog(ua, dlg, &dlg->local.tag) != PJ_SUCCESS) {
-	pj_mutex_unlock(ua->mutex);
-	pj_mutex_destroy(dlg->mutex);
-	pjsip_endpt_destroy_pool( ua->endpt, pool );
-	return NULL;
-    }
-    pj_mutex_unlock(ua->mutex);
-
-    PJ_LOG(4, (dlg->obj_name, "new %s dialog created", pjsip_role_name(role)));
-    return dlg;
-}
-
-/*
- * Destroy dialog.
- */
-PJ_DEF(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg )
-{
-    PJ_LOG(5, (dlg->obj_name, "destroying.."));
-
-    /* Lock dialog's mutex. 
-     * Check the mutex validity first since this function can be called
-     * on dialog initialization failure (which might be because mutex could not
-     * be allocated in the first place).
-     */
-    if (dlg->mutex) {
-	pj_mutex_lock(dlg->mutex);
-    }
-
-    /* This must be called while holding dialog's mutex, if any. */
-    pjsip_on_dialog_destroyed(dlg);
-
-    /* Lock UA. */
-    pj_mutex_lock(dlg->ua->mutex);
-
-    /* Erase from hash table. */
-    pj_hash_set( dlg->pool, dlg->ua->dlg_table,
-		 dlg->local.tag.ptr, dlg->local.tag.slen, NULL);
-
-    /* Erase from the list. */
-    pj_list_erase(dlg);
-
-    /* Unlock UA. */
-    pj_mutex_unlock(dlg->ua->mutex);
-
-    /* Unlock mutex. */
-    if (dlg->mutex) {
-	pj_mutex_unlock(dlg->mutex);
-    }
-
-    /* Destroy the pool. */
-    pjsip_endpt_destroy_pool( dlg->ua->endpt, dlg->pool);
-}
-
-/*
- * Dump user agent state to log file.
- */
-PJ_DEF(void) pjsip_ua_dump(pjsip_user_agent *ua)
-{
-#if PJ_LOG_MAX_LEVEL >= 3
-    PJ_LOG(3,(LOG_THIS, "Dumping user agent"));
-    PJ_LOG(3,(LOG_THIS, "  Pool capacity=%u, used=%u", 
-			pj_pool_get_capacity(ua->pool),
-			pj_pool_get_used_size(ua->pool)));
-    PJ_LOG(3,(LOG_THIS, "  Number of dialogs=%u", pj_hash_count(ua->dlg_table)));
-
-    if (pj_hash_count(ua->dlg_table)) {
-	pjsip_dlg *dlg;
-
-	PJ_LOG(3,(LOG_THIS, "  Dumping dialog list:"));
-	dlg = ua->dlg_list.next;
-	while (dlg != (pjsip_dlg*) &ua->dlg_list) {
-	    PJ_LOG(3, (LOG_THIS, "    %s %s", dlg->obj_name, 
-		       pjsip_dlg_state_str(dlg->state)));
-	    dlg = dlg->next;
-	}
-    }
-#endif
-}
-
Index: project/trunk/pjsip/src/pjsip-ua/sip_ua_private.h
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_ua_private.h	(revision 126)
+++ 	(revision )
@@ -1,36 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#ifndef __PJSIP_UA_PRIVATE_H__
-#define __PJSIP_UA_PRIVATE_H__
-
-
-/*
- * Internal dialog functions.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg,
-				       pjsip_rx_data *rdata );
-
-
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 
-			     pjsip_transaction *tsx, 
-			     pjsip_event *event);
-
-
-#endif	/* __PJSIP_UA_PRIVATE_H__ */
-
Index: /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 127)
@@ -349,4 +349,40 @@
     sess->cred_info = NULL;
     pj_list_init(&sess->cached_auth);
+
+    return PJ_SUCCESS;
+}
+
+
+/* Clone session. */
+PJ_DEF(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+					  pjsip_auth_clt_sess *sess,
+					  const pjsip_auth_clt_sess *rhs )
+{
+    unsigned i;
+
+    PJ_ASSERT_RETURN(pool && sess && rhs, PJ_EINVAL);
+
+    sess->pool = pool;
+    sess->endpt = (pjsip_endpoint*)rhs->endpt;
+    sess->cred_cnt = rhs->cred_cnt;
+    sess->cred_info = pj_pool_alloc(pool, 
+				    sess->cred_cnt*sizeof(pjsip_cred_info));
+    for (i=0; i<rhs->cred_cnt; ++i) {
+	pj_strdup(pool, &sess->cred_info[i].realm, &rhs->cred_info[i].realm);
+	pj_strdup(pool, &sess->cred_info[i].scheme, &rhs->cred_info[i].scheme);
+	pj_strdup(pool, &sess->cred_info[i].username, 
+		  &rhs->cred_info[i].username);
+	sess->cred_info[i].data_type = rhs->cred_info[i].data_type;
+	pj_strdup(pool, &sess->cred_info[i].data, &rhs->cred_info[i].data);
+    }
+
+    /* TODO note:
+     * Cloning the full authentication client is quite a big task.
+     * We do only the necessary bits here, i.e. cloning the credentials.
+     * The drawback of this basic approach is, a forked dialog will have to
+     * re-authenticate itself on the next request because it has lost the
+     * cached authentication headers.
+     */
+    PJ_TODO(FULL_CLONE_OF_AUTH_CLIENT_SESSION);
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 127)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 127)
@@ -0,0 +1,1138 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_util.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/guid.h>
+#include <pj/rand.h>
+#include <pj/array.h>
+#include <pj/except.h>
+#include <pj/hash.h>
+#include <pj/log.h>
+
+#define THIS_FILE	"sip_dialog.c"
+
+
+PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m)
+{
+    pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 10}};
+    pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}};
+
+    return m->id == PJSIP_INVITE_METHOD ||
+	   (pjsip_method_cmp(m, &subscribe)==0) ||
+	   (pjsip_method_cmp(m, &refer)==0);
+}
+
+static pj_status_t create_dialog( pjsip_user_agent *ua,
+				  pjsip_dialog **p_dlg)
+{
+    pjsip_endpoint *endpt;
+    pj_pool_t *pool;
+    pjsip_dialog *dlg;
+    pj_status_t status;
+
+    endpt = pjsip_ua_get_endpt(ua);
+    if (!endpt)
+	return PJ_EINVALIDOP;
+
+    pool = pjsip_endpt_create_pool(endpt, "dlg%p", 
+				   PJSIP_POOL_LEN_DIALOG, 
+				   PJSIP_POOL_INC_DIALOG);
+    if (!pool)
+	return PJ_ENOMEM;
+
+    dlg = pj_pool_zalloc(pool, sizeof(pjsip_dialog));
+    PJ_ASSERT_RETURN(dlg != NULL, PJ_ENOMEM);
+
+    dlg->pool = pool;
+    pj_sprintf(dlg->obj_name, "dlg%p", dlg);
+    dlg->ua = ua;
+
+    status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+
+    *p_dlg = dlg;
+    return PJ_SUCCESS;
+
+on_error:
+    if (dlg->mutex)
+	pj_mutex_destroy(dlg->mutex);
+    pjsip_endpt_release_pool(endpt, pool);
+    return status;
+}
+
+static void destroy_dialog( pjsip_dialog *dlg )
+{
+    if (dlg->mutex)
+	pj_mutex_destroy(dlg->mutex);
+    pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+}
+
+
+/*
+ * Create an UAC dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+					  const pj_str_t *local_uri,
+					  const pj_str_t *local_contact,
+					  const pj_str_t *remote_uri,
+					  const pj_str_t *target,
+					  pjsip_dialog **p_dlg)
+{
+    pj_status_t status;
+    pj_str_t tmp;
+    pjsip_dialog *dlg;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(ua && local_uri && remote_uri && p_dlg, PJ_EINVAL);
+
+    /* Create dialog instance. */
+    status = create_dialog(ua, &dlg);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Parse target. */
+    pj_strdup_with_null(dlg->pool, &tmp, target ? target : remote_uri);
+    dlg->target = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+    if (!dlg->target) {
+	status = PJSIP_EINVALIDURI;
+	goto on_error;
+    }
+
+    /* Init local info. */
+    dlg->local.info = pjsip_from_hdr_create(dlg->pool);
+    pj_strdup_with_null(dlg->pool, &tmp, local_uri);
+    dlg->local.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+    if (!dlg->local.info->uri) {
+	status = PJSIP_EINVALIDURI;
+	goto on_error;
+    }
+
+    /* Generate local tag. */
+    pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+    /* Calculate hash value of local tag. */
+    dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+				       dlg->local.info->tag.slen);
+
+    /* Randomize local CSeq. */
+    dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+    dlg->local.cseq = dlg->local.cseq;
+
+    /* Init local contact. */
+    dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+    pj_strdup_with_null(dlg->pool, &tmp, 
+			local_contact ? local_contact : local_uri);
+    dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+					      PJSIP_PARSE_URI_AS_NAMEADDR);
+    if (!dlg->local.contact->uri) {
+	status = PJSIP_EINVALIDURI;
+	goto on_error;
+    }
+
+    /* Init remote info. */
+    dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
+    pj_strdup_with_null(dlg->pool, &tmp, remote_uri);
+    dlg->remote.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+    if (!dlg->remote.info->uri) {
+	status = PJSIP_EINVALIDURI;
+	goto on_error;
+    }
+
+    /* Initialize remote's CSeq to -1. */
+    dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+    /* Initial role is UAC. */
+    dlg->role = PJSIP_ROLE_UAC;
+
+    /* Secure? */
+    dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+    /* Generate Call-ID header. */
+    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
+    pj_create_unique_string(dlg->pool, &dlg->call_id->id);
+
+    /* Initial route set is empty. */
+    pj_list_init(&dlg->route_set);
+
+    /* Init client authentication session. */
+    status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua), 
+				 dlg->pool, 0);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Register this dialog to user agent. */
+    status = pjsip_ua_register_dlg( ua, dlg );
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+
+    /* Done! */
+    *p_dlg = dlg;
+
+    return PJ_SUCCESS;
+
+on_error:
+    destroy_dialog(dlg);
+    return status;
+}
+
+
+/*
+ * Create UAS dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uas(   pjsip_user_agent *ua,
+					    pjsip_rx_data *rdata,
+					    const pj_str_t *contact,
+					    pjsip_dialog **p_dlg)
+{
+    pj_status_t status;
+    pjsip_hdr *contact_hdr;
+    pjsip_rr_hdr *rr;
+    pjsip_dialog *dlg;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(ua && rdata && p_dlg, PJ_EINVAL);
+
+    /* rdata must have request message. */
+    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
+		     PJSIP_ENOTREQUESTMSG);
+
+    /* Request must not have To tag. 
+     * This should have been checked in the user agent (or application?).
+     */
+    PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen == 0, PJ_EINVALIDOP);
+		     
+    /* The request must be a dialog establishing request. */
+    PJ_ASSERT_RETURN(
+	pjsip_method_creates_dialog(&rdata->msg_info.msg->line.req.method),
+	PJ_EINVALIDOP);
+
+    /* Create dialog instance. */
+    status = create_dialog(ua, &dlg);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init local info from the To header. */
+    dlg->local.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.to);
+    pjsip_fromto_hdr_set_from(dlg->local.info);
+
+    /* Generate local tag. */
+    pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+    /* Calculate hash value of local tag. */
+    dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+				       dlg->local.info->tag.slen);
+
+    /* Randomize local cseq */
+    dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+    dlg->local.cseq = dlg->local.first_cseq;
+
+    /* Init local contact. */
+    /* TODO:
+     *  Section 12.1.1, paragraph about using SIPS URI in Contact.
+     *  If the request that initiated the dialog contained a SIPS URI 
+     *  in the Request-URI or in the top Record-Route header field value, 
+     *  if there was any, or the Contact header field if there was no 
+     *  Record-Route header field, the Contact header field in the response
+     *  MUST be a SIPS URI.
+     */
+    if (contact) {
+	pj_str_t tmp;
+
+	dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+	pj_strdup_with_null(dlg->pool, &tmp, contact);
+	dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+						  PJSIP_PARSE_URI_AS_NAMEADDR);
+	if (!dlg->local.contact->uri) {
+	    status = PJSIP_EINVALIDURI;
+	    goto on_error;
+	}
+
+    } else {
+	dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+	dlg->local.contact->uri = dlg->local.info->uri;
+    }
+
+    /* Init remote info from the From header. */
+    dlg->remote.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.from);
+    pjsip_fromto_hdr_set_to(dlg->remote.info);
+
+    /* Init remote's contact from Contact header. */
+    contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, 
+				     NULL);
+    if (!contact_hdr) {
+	status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
+	goto on_error;
+    }
+    dlg->remote.contact = pjsip_hdr_clone(dlg->pool, contact_hdr);
+
+    /* Init remote's CSeq from CSeq header */
+    dlg->remote.cseq = dlg->remote.first_cseq = rdata->msg_info.cseq->cseq;
+
+    /* Set initial target to remote's Contact. */
+    dlg->target = dlg->remote.contact->uri;
+
+    /* Initial role is UAS */
+    dlg->role = PJSIP_ROLE_UAS;
+
+    /* Secure? 
+     *  RFC 3261 Section 12.1.1:
+     *  If the request arrived over TLS, and the Request-URI contained a 
+     *  SIPS URI, the 'secure' flag is set to TRUE.
+     */
+    dlg->secure = PJSIP_TRANSPORT_IS_SECURE(rdata->tp_info.transport) &&
+		  PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri);
+
+    /* Call-ID */
+    dlg->call_id = pjsip_hdr_clone(dlg->pool, rdata->msg_info.cid);
+
+    /* Route set. 
+     *  RFC 3261 Section 12.1.1:
+     *  The route set MUST be set to the list of URIs in the Record-Route 
+     *  header field from the request, taken in order and preserving all URI 
+     *  parameters. If no Record-Route header field is present in the request,
+     * the route set MUST be set to the empty set.
+     */
+    pj_list_init(&dlg->route_set);
+    rr = rdata->msg_info.record_route;
+    while (rr != NULL) {
+	pjsip_route_hdr *route;
+
+	/* Clone the Record-Route, change the type to Route header. */
+	route = pjsip_hdr_clone(dlg->pool, rr);
+	pjsip_routing_hdr_set_route(route);
+
+	/* Add to route set. */
+	pj_list_push_back(&dlg->route_set, route);
+
+	/* Find next Record-Route header. */
+	rr = rr->next;
+	if (rr == (pjsip_rr_hdr*)&rdata->msg_info.msg->hdr)
+	    break;
+	rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, rr);
+    }
+
+    /* Init client authentication session. */
+    status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua),
+				 dlg->pool, 0);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Calculate hash value of remote tag. */
+    dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr, 
+					dlg->remote.info->tag.slen);
+
+    /* Register this dialog to user agent. */
+    status = pjsip_ua_register_dlg( ua, dlg );
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Put this dialog in rdata's mod_data */
+    rdata->endpt_info.mod_data[ua->id] = dlg;
+
+    PJ_TODO(DIALOG_APP_TIMER);
+
+    /* Done. */
+    *p_dlg = dlg;
+    return PJ_SUCCESS;
+
+on_error:
+    destroy_dialog(dlg);
+    return status;
+}
+
+
+/*
+ * Create forked dialog from a response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
+				    const pjsip_rx_data *rdata,
+				    pjsip_dialog **new_dlg )
+{
+    pjsip_dialog *dlg;
+    const pjsip_route_hdr *r;
+    pj_status_t status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(first_dlg && rdata && new_dlg, PJ_EINVAL);
+    
+    /* rdata must be response message. */
+    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
+		     PJSIP_ENOTRESPONSEMSG);
+
+    /* To tag must present in the response. */
+    PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
+
+    /* Create the dialog. */
+    status = create_dialog((pjsip_user_agent*)first_dlg->ua, &dlg);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Clone remote target. */
+    dlg->target = pjsip_uri_clone(dlg->pool, first_dlg->target);
+
+    /* Clone local info. */
+    dlg->local.info = pjsip_hdr_clone(dlg->pool, first_dlg->local.info);
+
+    /* Clone local tag. */
+    pj_strdup(dlg->pool, &dlg->local.info->tag, &first_dlg->local.info->tag);
+    dlg->local.tag_hval = first_dlg->local.tag_hval;
+
+    /* Clone local CSeq. */
+    dlg->local.first_cseq = first_dlg->local.first_cseq;
+    dlg->local.cseq = first_dlg->local.cseq;
+
+    /* Clone local Contact. */
+    dlg->local.contact = pjsip_hdr_clone(dlg->pool, first_dlg->local.contact);
+
+    /* Clone remote info. */
+    dlg->remote.info = pjsip_hdr_clone(dlg->pool, first_dlg->remote.info);
+
+    /* Set remote tag from the response. */
+    pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+
+    /* Initialize remote's CSeq to -1. */
+    dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+    /* Initial role is UAC. */
+    dlg->role = PJSIP_ROLE_UAC;
+
+    /* Secure? */
+    dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+    /* Clone Call-ID header. */
+    dlg->call_id = pjsip_hdr_clone(dlg->pool, first_dlg->call_id);
+
+    /* Duplicate Route-Set. */
+    pj_list_init(&dlg->route_set);
+    r = first_dlg->route_set.next;
+    while (r != &first_dlg->route_set) {
+	pjsip_route_hdr *h;
+
+	h = pjsip_hdr_clone(dlg->pool, r);
+	pj_list_push_back(&dlg->route_set, h);
+
+	r = r->next;
+    }
+
+    /* Init client authentication session. */
+    status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess, 
+				  &first_dlg->auth_sess);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Register this dialog to user agent. */
+    status = pjsip_ua_register_dlg(dlg->ua, dlg );
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+
+    /* Done! */
+    *new_dlg = dlg;
+
+    return PJ_SUCCESS;
+
+on_error:
+    destroy_dialog(dlg);
+    return status;
+}
+
+
+/*
+ * Destroy dialog.
+ */
+static pj_status_t unregister_and_destroy_dialog( pjsip_dialog *dlg )
+{
+    pj_status_t status;
+
+    /* Lock must have been held. */
+
+    /* Check dialog state. */
+    /* Number of sessions must be zero. */
+    PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP);
+
+    /* MUST not have pending transactions. */
+    PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP);
+
+    /* Unregister from user agent. */
+    status = pjsip_ua_unregister_dlg(dlg->ua, dlg);
+    if (status != PJ_SUCCESS) {
+	pj_assert(!"Unexpected failed unregistration!");
+	return status;
+    }
+
+    /* Destroy this dialog. */
+    pj_mutex_destroy(dlg->mutex);
+    pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set route_set
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+					     const pjsip_route_hdr *route_set )
+{
+    pjsip_route_hdr *r;
+
+    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+    pj_mutex_lock(dlg->mutex);
+
+    /* Clear route set. */
+    pj_list_init(&dlg->route_set);
+
+    if (!route_set) {
+	pj_mutex_unlock(dlg->mutex);
+	return PJ_SUCCESS;
+    }
+
+    r = route_set->next;
+    while (r != route_set) {
+	pjsip_route_hdr *new_r;
+
+	new_r = pjsip_hdr_clone(dlg->pool, r);
+	pj_list_push_back(&dlg->route_set, new_r);
+
+	r = r->next;
+    }
+
+    pj_mutex_unlock(dlg->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Increment session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg )
+{
+    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+    pj_mutex_lock(dlg->mutex);
+    ++dlg->sess_count;
+    pj_mutex_unlock(dlg->mutex);
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Decrement session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg )
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+    pj_mutex_lock(dlg->mutex);
+
+    --dlg->sess_count;
+
+    if (dlg->sess_count==0 && dlg->tsx_count==0)
+	status = unregister_and_destroy_dialog(dlg);
+    else {
+	pj_mutex_unlock(dlg->mutex);
+	status = PJ_SUCCESS;
+    }
+
+    return status;
+}
+
+
+/*
+ * Add usage.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+					 pjsip_module *mod,
+					 void *mod_data )
+{
+    unsigned index;
+
+    PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
+    PJ_ASSERT_RETURN(mod->id >= 0 && mod->id < PJSIP_MAX_MODULE,
+		     PJ_EINVAL);
+    PJ_ASSERT_RETURN(dlg->usage_cnt < PJSIP_MAX_MODULE, PJ_EBUG);
+
+    pj_mutex_lock(dlg->mutex);
+
+    /* Usages are sorted on priority, lowest number first.
+     * Find position to put the new module, also makes sure that
+     * this module has not been registered before.
+     */
+    for (index=0; index<dlg->usage_cnt; ++index) {
+	if (dlg->usage[index] == mod) {
+	    pj_assert(!"This module is already registered");
+	    pj_mutex_unlock(dlg->mutex);
+	    return PJSIP_ETYPEEXISTS;
+	}
+
+	if (dlg->usage[index]->priority > mod->priority)
+	    break;
+    }
+
+    /* index holds position to put the module.
+     * Insert module at this index.
+     */
+    pj_array_insert(dlg->usage, sizeof(dlg->usage[0]), dlg->usage_cnt,
+		    index, &mod);
+    
+    /* Set module data. */
+    dlg->mod_data[mod->id] = mod_data;
+
+    pj_mutex_unlock(dlg->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Create a new request within dialog (i.e. after the dialog session has been
+ * established). The construction of such requests follows the rule in 
+ * RFC3261 section 12.2.1.
+ */
+static pj_status_t dlg_create_request_throw( pjsip_dialog *dlg,
+					     const pjsip_method *method,
+					     int cseq,
+					     pjsip_tx_data **p_tdata )
+{
+    pjsip_tx_data *tdata;
+    pjsip_contact_hdr *contact;
+    pjsip_route_hdr *route, *end_list;
+    pj_status_t status;
+
+    /* Contact Header field.
+     * Contact can only be present in requests that establish dialog (in the 
+     * core SIP spec, only INVITE).
+     */
+    if (pjsip_method_creates_dialog(method))
+	contact = dlg->local.contact;
+    else
+	contact = NULL;
+
+    /*
+     * Create the request by cloning from the headers in the
+     * dialog.
+     */
+    status = pjsip_endpt_create_request_from_hdr(pjsip_ua_get_endpt(dlg->ua),
+						 method,
+						 dlg->target,
+						 dlg->local.info,
+						 dlg->remote.info,
+						 contact,
+						 dlg->call_id,
+						 cseq,
+						 NULL,
+						 &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Just copy dialog route-set to Route header. 
+     * The transaction will do the processing as specified in Section 12.2.1
+     * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
+     */
+    route = dlg->route_set.next;
+    end_list = &dlg->route_set;
+    for (; route != end_list; route = route->next ) {
+	pjsip_route_hdr *r;
+	r = pjsip_hdr_shallow_clone( tdata->pool, route );
+	pjsip_routing_hdr_set_route(r);
+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
+    }
+
+    /* Copy authorization headers. */
+    status = pjsip_auth_clt_init_req( &dlg->auth_sess, tdata );
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Done. */
+    *p_tdata = tdata;
+
+    return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Create outgoing request.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
+					      const pjsip_method *method,
+					      int cseq,
+					      pjsip_tx_data **p_tdata)
+{
+    pj_status_t status;
+    pjsip_tx_data *tdata = NULL;
+    PJ_USE_EXCEPTION;
+
+    PJ_ASSERT_RETURN(dlg && method && p_tdata, PJ_EINVAL);
+
+    /* Lock dialog. */
+    pj_mutex_lock(dlg->mutex);
+
+    /* Use outgoing CSeq and increment it by one. */
+    if (cseq <= 0)
+	cseq = dlg->local.cseq + 1;
+
+    /* Keep compiler happy */
+    status = PJ_EBUG;
+
+    /* Create the request. */
+    PJ_TRY {
+	status = dlg_create_request_throw(dlg, method, cseq, &tdata);
+    }
+    PJ_CATCH_ANY {
+	status = PJ_ENOMEM;
+    }
+    PJ_END;
+
+    /* Failed! Delete transmit data. */
+    if (status != PJ_SUCCESS && tdata) {
+	pjsip_tx_data_dec_ref( tdata );
+	tdata = NULL;
+    }
+
+    /* Unlock dialog. */
+    pj_mutex_unlock(dlg->mutex);
+
+    *p_tdata = tdata;
+
+    return status;
+}
+
+
+/*
+ * Update CSeq in outgoing request to reflect the dialog.
+ * Then increment local CSeq.
+ */
+static void update_cseq( pjsip_dialog *dlg,
+			 pjsip_tx_data *tdata )
+{
+    pjsip_msg *msg = tdata->msg;
+
+    /* Start locking the dialog. */
+    pj_mutex_lock(dlg->mutex);
+
+    /* Update dialog's CSeq and message's CSeq if request is not
+     * ACK nor CANCEL.
+     */
+    if (msg->line.req.method.id != PJSIP_CANCEL_METHOD &&
+	msg->line.req.method.id != PJSIP_ACK_METHOD) 
+    {
+	pjsip_cseq_hdr *ch;
+	
+	ch = PJSIP_MSG_CSEQ_HDR(msg);
+	PJ_ASSERT_ON_FAIL(ch!=NULL, return);
+
+	ch->cseq = dlg->local.cseq++;
+
+	/* Force the whole message to be re-printed. */
+	pjsip_tx_data_invalidate_msg( tdata );
+    }
+
+}
+
+/*
+ * Send request statefully, and update dialog'c CSeq.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
+					    pjsip_tx_data *tdata,
+					    pjsip_transaction **p_tsx )
+{
+    pjsip_transaction *tsx;
+    pj_status_t status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
+		     PJSIP_ENOTREQUESTMSG);
+
+    /* Update CSeq */
+    update_cseq(dlg, tdata);
+
+    /* Create a new transaction. 
+     * The transaction user is the user agent module.
+     */
+    status = pjsip_tsx_create_uac(dlg->ua, tdata, &tsx);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Attach this dialog to the transaction, so that user agent
+     * will dispatch events to this dialog.
+     */
+    tsx->mod_data[dlg->ua->id] = dlg;
+
+    /* Increment transaction counter. */
+    ++dlg->tsx_count;
+
+    /* Send the message. */
+    status = pjsip_tsx_send_msg(tsx, tdata);
+    if (status != PJ_SUCCESS) {
+	pjsip_tsx_terminate(tsx, tsx->status_code);
+	goto on_error;
+    }
+
+    /* Done. */
+    *p_tsx = tsx;
+
+    /* Unlock dialog. */
+    pj_mutex_unlock(dlg->mutex);
+
+    return PJ_SUCCESS;
+
+on_error:
+    /* Unlock dialog. */
+    pj_mutex_unlock(dlg->mutex);
+   
+    /* Whatever happen delete the message. */
+    pjsip_tx_data_dec_ref( tdata );
+
+    *p_tsx = NULL;
+    return status;
+}
+
+
+/*
+ * Create response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_response(	pjsip_dialog *dlg,
+						pjsip_rx_data *rdata,
+						int st_code,
+						const pj_str_t *st_text,
+						pjsip_tx_data **p_tdata)
+{
+    pj_status_t status;
+    pjsip_cseq_hdr *cseq;
+    pjsip_tx_data *tdata;
+    int st_class;
+
+    /* Create generic response. */
+    status = pjsip_endpt_create_response(pjsip_ua_get_endpt(dlg->ua),
+					 rdata, st_code, st_text, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Lock the dialog. */
+    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(pjsip_ua_get_endpt(dlg->ua),
+					       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(pjsip_ua_get_endpt(dlg->ua),
+					       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;
+    }
+
+    /* Unlock the dialog. */
+    pj_mutex_unlock(dlg->mutex);
+
+    /* Done. */
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Modify response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_modify_response(	pjsip_dialog *dlg,
+						pjsip_tx_data *tdata,
+						int st_code,
+						const pj_str_t *st_text)
+{
+    
+    PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+		     PJSIP_ENOTRESPONSEMSG);
+    PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
+
+    tdata->msg->line.status.code = st_code;
+    if (st_text) {
+	pj_strdup(tdata->pool, &tdata->msg->line.status.reason, st_text);
+    } else {
+	tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Send response statefully.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_response( pjsip_dialog *dlg,
+					     pjsip_transaction *tsx,
+					     pjsip_tx_data *tdata)
+{
+    /* Sanity check. */
+    PJ_ASSERT_RETURN(dlg && tsx && tdata && tdata->msg, PJ_EINVAL);
+    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+		     PJSIP_ENOTRESPONSEMSG);
+
+    /* The transaction must belong to this dialog.  */
+    PJ_ASSERT_RETURN(tsx->mod_data[dlg->ua->id] == dlg, PJ_EINVALIDOP);
+
+    /* Check that transaction method and cseq match the response. 
+     * This operation is sloooww (search CSeq header twice), that's why
+     * we only do it in debug mode.
+     */
+#if defined(PJ_DEBUG) && PJ_DEBUG!=0
+    PJ_ASSERT_RETURN( PJSIP_MSG_CSEQ_HDR(tdata->msg)->cseq == tsx->cseq &&
+		      pjsip_method_cmp(&PJSIP_MSG_CSEQ_HDR(tdata->msg)->method, 
+				       &tsx->method)==0,
+		      PJ_EINVALIDOP);
+#endif
+
+    return pjsip_tsx_send_msg(tsx, tdata);
+}
+
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+    pj_status_t status;
+    pjsip_transaction *tsx;
+    unsigned i;
+
+    /* Lock the dialog. */
+    pj_mutex_lock(dlg->mutex);
+
+    /* 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;
+
+    /* Report the request to dialog usages. */
+    for (i=0; i<dlg->usage_cnt; ++i) {
+	pj_bool_t processed;
+
+	if (!dlg->usage[i]->on_rx_request)
+	    continue;
+
+	processed = (*dlg->usage[i]->on_rx_request)(rdata);
+
+	if (processed)
+	    break;
+    }
+
+    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(pjsip_ua_get_endpt(dlg->ua), 
+					     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);
+	}
+    }
+
+on_return:
+    /* Unlock dialog. */
+    pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+    unsigned i;
+
+    /* Lock the dialog. */
+    pj_mutex_lock(dlg->mutex);
+
+    /* Update the remote tag, if none is specified yet. */
+    if (dlg->remote.info->tag.slen == 0 && rdata->msg_info.to->tag.slen != 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. */
+    }
+
+    /* Check that rdata already has dialog in mod_data. */
+    pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);
+
+    /* Pass to dialog usages. */
+    for (i=0; i<dlg->usage_cnt; ++i) {
+	pj_bool_t processed;
+
+	if (!dlg->usage[i]->on_rx_response)
+	    continue;
+
+	processed = (*dlg->usage[i]->on_rx_response)(rdata);
+
+	if (processed)
+	    break;
+    }
+
+    if (i==dlg->usage_cnt) {
+	PJ_LOG(4,(dlg->obj_name, "%s is unhandled by dialog usages",
+		  pjsip_rx_data_get_info(rdata)));
+    }
+
+    /* Unlock dialog. */
+    pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving transaction
+ * state notification.
+ */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+			     pjsip_transaction *tsx,
+			     pjsip_event *e )
+{
+    unsigned i;
+
+    /* Lock the dialog. */
+    pj_mutex_lock(dlg->mutex);
+
+    if (tsx->state == PJSIP_TSX_STATE_TERMINATED)
+	--dlg->tsx_count;
+
+    /* Pass to dialog usages. */
+    for (i=0; i<dlg->usage_cnt; ++i) {
+
+	if (!dlg->usage[i]->on_tsx_state)
+	    continue;
+
+	(*dlg->usage[i]->on_tsx_state)(tsx, e);
+    }
+
+    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 && 
+	dlg->sess_count == 0) 
+    {
+	/* Time to destroy dialog. */
+	unregister_and_destroy_dialog(dlg);
+
+    } else {
+	/* Unlock dialog. */
+	pj_mutex_unlock(dlg->mutex);
+    }
+}
+
+
Index: /pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 127)
@@ -78,15 +78,9 @@
     pjsip_module	 module_list;
 
-    /** Number of supported methods. */
-    unsigned		 method_cnt;
-
-    /** Array of supported methods. */
-    const pjsip_method	*methods[MAX_METHODS];
-
-    /** Allow header. */
-    pjsip_allow_hdr	*allow_hdr;
-
     /** Route header list. */
     pjsip_route_hdr	 route_hdr_list;
+
+    /** Capability header list. */
+    pjsip_hdr		 cap_hdr;
 
     /** Additional request headers. */
@@ -197,5 +191,4 @@
 
     /* Done. */
-    PJ_TODO(BUILD_ALLOW_HEADER_BASED_ON_MODULES_SUPPORTED_METHODS);
 
 on_return:
@@ -249,6 +242,4 @@
     status = PJ_SUCCESS;
 
-    PJ_TODO(REMOVE_METHODS_FROM_ALLOW_HEADER_WHEN_MODULE_IS_UNREGISTERED);
-
 on_return:
     pj_rwmutex_unlock_write(endpt->mod_mutex);
@@ -256,10 +247,79 @@
 }
 
-/*
- * Get "Allow" header.
- */
-PJ_DEF(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
-{
-    return endpt->allow_hdr;
+
+/*
+ * Get the value of the specified capability header field.
+ */
+PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+						     int htype,
+						     const pj_str_t *hname)
+{
+    pjsip_hdr *hdr = endpt->cap_hdr.next;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(endpt != NULL, NULL);
+    PJ_ASSERT_RETURN(htype != PJSIP_H_OTHER || hname, NULL);
+
+    if (htype != PJSIP_H_OTHER) {
+	while (hdr != &endpt->cap_hdr) {
+	    if (hdr->type == htype)
+		return hdr;
+	    hdr = hdr->next;
+	}
+    }
+    return NULL;
+}
+
+
+/*
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+						pjsip_module *mod,
+						int htype,
+						const pj_str_t *hname,
+						unsigned count,
+						const pj_str_t tags[])
+{
+    pjsip_generic_array_hdr *hdr;
+    unsigned i;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(endpt!=NULL && mod!=NULL && count>0 && tags, PJ_EINVAL);
+    PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT || 
+		     htype==PJSIP_H_ALLOW ||
+		     htype==PJSIP_H_SUPPORTED,
+		     PJ_EINVAL);
+
+    /* Find the header. */
+    hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt, 
+								htype, hname);
+
+    /* Create the header when it's not present */
+    if (hdr == NULL) {
+	switch (htype) {
+	case PJSIP_H_ACCEPT:
+	    hdr = pjsip_accept_hdr_create(endpt->pool);
+	    break;
+	case PJSIP_H_ALLOW:
+	    hdr = pjsip_allow_hdr_create(endpt->pool);
+	    break;
+	case PJSIP_H_SUPPORTED:
+	    hdr = pjsip_supported_hdr_create(endpt->pool);
+	    break;
+	default:
+	    return PJ_EINVAL;
+	}
+    }
+
+    /* Add the tags to the header. */
+    for (i=0; i<count; ++i) {
+	pj_strdup(endpt->pool, &hdr->values[hdr->count], &tags[i]);
+	++hdr->count;
+    }
+
+    /* Done. */
+    return PJ_SUCCESS;
 }
 
@@ -326,5 +386,5 @@
     pj_pool_t *pool;
     pjsip_endpoint *endpt;
-    pjsip_max_forwards_hdr *mf_hdr;
+    pjsip_max_fwd_hdr *mf_hdr;
     pj_lock_t *lock = NULL;
 
@@ -420,7 +480,10 @@
 
     /* Add "Max-Forwards" for request header. */
-    mf_hdr = pjsip_max_forwards_hdr_create(endpt->pool);
-    mf_hdr->ivalue = PJSIP_MAX_FORWARDS_VALUE;
+    mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,
+				      PJSIP_MAX_FORWARDS_VALUE);
     pj_list_insert_before( &endpt->req_hdr, mf_hdr);
+
+    /* Initialize capability header list. */
+    pj_list_init(&endpt->cap_hdr);
 
     /* Done. */
Index: /pjproject/trunk/pjsip/src/pjsip/sip_errno.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_errno.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_errno.c	(revision 127)
@@ -46,4 +46,5 @@
     { PJSIP_EINVALIDSTATUS,	"Invalid status code"},
 
+    { PJSIP_EINVALIDURI,	"Invalid URI" },
     { PJSIP_EINVALIDSCHEME,	"Invalid URI scheme" },
     { PJSIP_EMISSINGREQURI,	"Missing Request-URI" },
@@ -78,5 +79,8 @@
     { PJSIP_EAUTHACCDISABLED,	"Account or credential is disabled" },
     { PJSIP_EAUTHINVALIDREALM,	"Invalid authorization realm"},
-    { PJSIP_EAUTHINVALIDDIGEST,	"Invalid authorization digest" }
+    { PJSIP_EAUTHINVALIDDIGEST,	"Invalid authorization digest" },
+
+    /* UA/dialog layer. */
+    { PJSIP_EMISSINGTAG,	"Missing From/To tag parameter" }
 };
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_msg.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_msg.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_msg.c	(revision 127)
@@ -499,8 +499,12 @@
 };
 
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
-						     const pj_str_t *hnames )
-{
-    pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+PJ_DEF(pjsip_generic_string_hdr*) 
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+			       void *mem,
+			       const pj_str_t *hnames,
+			       const pj_str_t *hvalue)
+{
+    pjsip_generic_string_hdr *hdr = mem;
+
     init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
     if (hnames) {
@@ -508,20 +512,25 @@
 	hdr->sname = hdr->name;
     }
-    hdr->hvalue.ptr = NULL;
-    hdr->hvalue.slen = 0;
-    return hdr;
-}
-
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
-							       const pj_str_t *hname,
-							       const pj_str_t *hvalue)
-{
-    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, hname);
-    pj_strdup(pool, &hdr->hvalue, hvalue);
-    return hdr;
-}
-
-static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr, 
-				    char *buf, pj_size_t size)
+    if (hvalue) {
+	pj_strdup(pool, &hdr->hvalue, hvalue);
+    } else {
+	hdr->hvalue.ptr = NULL;
+	hdr->hvalue.slen = 0;
+    }
+
+    return hdr;
+}
+
+PJ_DEF(pjsip_generic_string_hdr*) 
+pjsip_generic_string_hdr_create( pj_pool_t *pool,
+				 const pj_str_t *hnames,
+				 const pj_str_t *hvalue)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+    return pjsip_generic_string_hdr_init(pool, mem, hnames, hvalue);
+}
+
+static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
+					   char *buf, pj_size_t size)
 {
     char *p = buf;
@@ -544,9 +553,10 @@
 					           const pjsip_generic_string_hdr *rhs)
 {
-    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, &rhs->name);
+    pjsip_generic_string_hdr *hdr;
+    
+    hdr = pjsip_generic_string_hdr_create(pool, &rhs->name, &rhs->hvalue);
 
     hdr->type = rhs->type;
     hdr->sname = hdr->name;
-    pj_strdup( pool, &hdr->hvalue, &rhs->hvalue);
     return hdr;
 }
@@ -579,8 +589,11 @@
 };
 
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
-						     const pj_str_t *hnames )
-{
-    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init(  pj_pool_t *pool,
+							    void *mem,
+							    const pj_str_t *hnames,
+							    int value)
+{
+    pjsip_generic_int_hdr *hdr = mem;
+
     init_hdr(hdr, PJSIP_H_OTHER, &generic_int_hdr_vptr);
     if (hnames) {
@@ -588,15 +601,14 @@
 	hdr->sname = hdr->name;
     }
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
-							       const pj_str_t *hname,
-							       int value)
-{
-    pjsip_generic_int_hdr *hdr = pjsip_generic_int_hdr_create(pool, hname);
     hdr->ivalue = value;
     return hdr;
+}
+
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+						     const pj_str_t *hnames,
+						     int value)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+    return pjsip_generic_int_hdr_init(pool, mem, hnames, value);
 }
 
@@ -652,8 +664,11 @@
 };
 
-PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
-							     const pj_str_t *hnames)
-{
-    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init( pj_pool_t *pool,
+							       void *mem,
+							       const pj_str_t *hnames)
+{
+    pjsip_generic_array_hdr *hdr = mem;
+
     init_hdr(hdr, PJSIP_H_OTHER, &generic_array_hdr_vptr);
     if (hnames) {
@@ -663,4 +678,11 @@
     hdr->count = 0;
     return hdr;
+}
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create( pj_pool_t *pool,
+							     const pj_str_t *hnames)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+    return pjsip_generic_array_hdr_init(pool, mem, hnames);
 
 }
@@ -714,7 +736,11 @@
  * Accept header.
  */
-PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
-{
-    pjsip_accept_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+						 void *mem )
+{
+    pjsip_accept_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_ACCEPT, &generic_array_hdr_vptr);
     hdr->count = 0;
@@ -722,4 +748,10 @@
 }
 
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_accept_hdr));
+    return pjsip_accept_hdr_init(pool, mem);
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -728,7 +760,11 @@
  */
 
-PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
-{
-    pjsip_allow_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+					       void *mem )
+{
+    pjsip_allow_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_ALLOW, &generic_array_hdr_vptr);
     hdr->count = 0;
@@ -736,4 +772,10 @@
 }
 
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_allow_hdr));
+    return pjsip_allow_hdr_init(pool, mem);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /*
@@ -741,9 +783,20 @@
  */
 
+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+					   void *mem )
+{
+    pjsip_cid_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);
+    return hdr;
+
+}
+
 PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
 {
-    pjsip_cid_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);
-    return hdr;
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_cid_hdr));
+    return pjsip_cid_hdr_init(pool, mem);
 }
 
@@ -764,10 +817,20 @@
 };
 
-PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
-{
-    pjsip_clen_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+					     void *mem )
+{
+    pjsip_clen_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_CONTENT_LENGTH, &clen_hdr_vptr);
     hdr->len = 0;
     return hdr;
+}
+
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+    return pjsip_clen_hdr_init(pool, mem);
 }
 
@@ -816,7 +879,11 @@
 };
 
-PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
-{
-    pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+					     void *mem )
+{
+    pjsip_cseq_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_CSEQ, &cseq_hdr_vptr);
     hdr->cseq = 0;
@@ -827,4 +894,10 @@
 }
 
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+    return pjsip_cseq_hdr_init(pool, mem);
+}
+
 static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size)
 {
@@ -885,11 +958,22 @@
 };
 
-PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
-{
-    pjsip_contact_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+						   void *mem )
+{
+    pjsip_contact_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    pj_memset(mem, 0, sizeof(pjsip_contact_hdr));
     init_hdr(hdr, PJSIP_H_CONTACT, &contact_hdr_vptr);
     hdr->expires = -1;
     pj_list_init(&hdr->other_param);
     return hdr;
+}
+
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_contact_hdr));
+    return pjsip_contact_hdr_init(pool, mem);
 }
 
@@ -1003,9 +1087,21 @@
 };
 
+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+					       void *mem )
+{
+    pjsip_ctype_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    pj_memset(mem, 0, sizeof(pjsip_ctype_hdr));
+    init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
+    return hdr;
+
+}
+
 PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
 {
-    pjsip_ctype_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
-    return hdr;
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_ctype_hdr));
+    return pjsip_ctype_hdr_init(pool, mem);
 }
 
@@ -1067,10 +1163,23 @@
  * Expires header.
  */
-PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool )
-{
-    pjsip_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+						   void *mem,
+						   int value)
+{
+    pjsip_expires_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_EXPIRES, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
+    hdr->ivalue = value;
+    return hdr;
+
+}
+
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+						     int value )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_expires_hdr));
+    return pjsip_expires_hdr_init(pool, mem, value);
 }
 
@@ -1094,7 +1203,12 @@
 };
 
-PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
-{
-    pjsip_from_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+					     void *mem )
+{
+    pjsip_from_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    pj_memset(mem, 0, sizeof(pjsip_from_hdr));
     init_hdr(hdr, PJSIP_H_FROM, &fromto_hdr_vptr);
     pj_list_init(&hdr->other_param);
@@ -1102,13 +1216,31 @@
 }
 
-PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
-{
-    pjsip_to_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_from_hdr));
+    return pjsip_from_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+					 void *mem )
+{
+    pjsip_to_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    pj_memset(mem, 0, sizeof(pjsip_to_hdr));
     init_hdr(hdr, PJSIP_H_TO, &fromto_hdr_vptr);
     pj_list_init(&hdr->other_param);
     return hdr;
-}
-
-PJ_DEF(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr )
+
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_to_hdr));
+    return pjsip_to_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr )
 {
     hdr->type = PJSIP_H_FROM;
@@ -1117,5 +1249,5 @@
 }
 
-PJ_DEF(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr )
+PJ_DEF(pjsip_to_hdr*) pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr )
 {
     hdr->type = PJSIP_H_TO;
@@ -1184,10 +1316,23 @@
  * Max-Forwards header.
  */
-PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
-{
-    pjsip_max_forwards_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_init( pj_pool_t *pool,
+						   void *mem,
+						   int value)
+{
+    pjsip_max_fwd_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_MAX_FORWARDS, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
+    hdr->ivalue = value;
+    return hdr;
+
+}
+
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_create(pj_pool_t *pool,
+						    int value)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_max_fwd_hdr));
+    return pjsip_max_fwd_hdr_init(pool, mem, value);
 }
 
@@ -1197,10 +1342,22 @@
  * Min-Expires header.
  */
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool)
-{
-    pjsip_min_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+							   void *mem,
+							   int value )
+{
+    pjsip_min_expires_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_MIN_EXPIRES, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
+    hdr->ivalue = value;
+    return hdr;
+}
+
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+							    int value )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_min_expires_hdr));
+    return pjsip_min_expires_hdr_init(pool, mem, value );
 }
 
@@ -1220,20 +1377,41 @@
 };
 
-PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
-{
-    pjsip_rr_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+					 void *mem )
+{
+    pjsip_rr_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_RECORD_ROUTE, &routing_hdr_vptr);
     pjsip_name_addr_init(&hdr->name_addr);
     pj_list_init(&hdr->other_param);
     return hdr;
-}
-
-PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
-{
-    pjsip_route_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+
+}
+
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_rr_hdr));
+    return pjsip_rr_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+					       void *mem )
+{
+    pjsip_route_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_ROUTE, &routing_hdr_vptr);
     pjsip_name_addr_init(&hdr->name_addr);
     pj_list_init(&hdr->other_param);
     return hdr;
+}
+
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_route_hdr));
+    return pjsip_route_hdr_init(pool, mem);
 }
 
@@ -1305,7 +1483,11 @@
  * Require header.
  */
-PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
-{
-    pjsip_require_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+						   void *mem )
+{
+    pjsip_require_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_REQUIRE, &generic_array_hdr_vptr);
     hdr->count = 0;
@@ -1313,14 +1495,32 @@
 }
 
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_require_hdr));
+    return pjsip_require_hdr_init(pool, mem);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /*
  * Retry-After header.
  */
-PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool)
-{
-    pjsip_retry_after_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+							   void *mem,
+							   int value )
+{
+    pjsip_retry_after_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_RETRY_AFTER, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
+    hdr->ivalue = value;
+    return hdr;
+}
+
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+							    int value )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_retry_after_hdr));
+    return pjsip_retry_after_hdr_init(pool, mem, value );
 }
 
@@ -1330,7 +1530,10 @@
  * Supported header.
  */
-PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
-{
-    pjsip_supported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+						       void *mem )
+{
+    pjsip_supported_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
     init_hdr(hdr, PJSIP_H_SUPPORTED, &generic_array_hdr_vptr);
     hdr->count = 0;
@@ -1338,4 +1541,10 @@
 }
 
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_supported_hdr));
+    return pjsip_supported_hdr_init(pool, mem);
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1343,10 +1552,20 @@
  * Unsupported header.
  */
-PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
-{
-    pjsip_unsupported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+							   void *mem )
+{
+    pjsip_unsupported_hdr *hdr = mem;
+    
+    PJ_UNUSED_ARG(pool);
+
     init_hdr(hdr, PJSIP_H_UNSUPPORTED, &generic_array_hdr_vptr);
     hdr->count = 0;
     return hdr;
+}
+
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_unsupported_hdr));
+    return pjsip_unsupported_hdr_init(pool, mem);
 }
 
@@ -1366,13 +1585,24 @@
 };
 
-PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
-{
-    pjsip_via_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+					   void *mem )
+{
+    pjsip_via_hdr *hdr = mem;
+
+    PJ_UNUSED_ARG(pool);
+
+    pj_memset(mem, 0, sizeof(pjsip_via_hdr));
     init_hdr(hdr, PJSIP_H_VIA, &via_hdr_vptr);
-    //hdr->sent_by.port = 5060;
     hdr->ttl_param = -1;
     hdr->rport_param = -1;
     pj_list_init(&hdr->other_param);
     return hdr;
+
+}
+
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
+{
+    void *mem = pj_pool_alloc(pool, sizeof(pjsip_via_hdr));
+    return pjsip_via_hdr_init(pool, mem);
 }
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_parser.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_parser.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_parser.c	(revision 127)
@@ -1168,8 +1168,8 @@
 
     if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
-	url = pjsip_url_create(pool, 0);
+	url = pjsip_sip_uri_create(pool, 0);
 
     } else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
-	url = pjsip_url_create(pool, 1);
+	url = pjsip_sip_uri_create(pool, 1);
 
     } else {
@@ -1542,5 +1542,5 @@
 static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx)
 {
-    pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool);
+    pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool, 0);
     parse_generic_int_hdr(hdr, ctx->scanner);
     return (pjsip_hdr*)hdr;
@@ -1602,5 +1602,5 @@
 {
     pjsip_retry_after_hdr *hdr;
-    hdr = pjsip_retry_after_hdr_create(ctx->pool);
+    hdr = pjsip_retry_after_hdr_create(ctx->pool, 0);
     parse_generic_int_hdr(hdr, ctx->scanner);
     return (pjsip_hdr*)hdr;
@@ -1674,6 +1674,6 @@
 static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
 {
-    pjsip_max_forwards_hdr *hdr;
-    hdr = pjsip_max_forwards_hdr_create(ctx->pool);
+    pjsip_max_fwd_hdr *hdr;
+    hdr = pjsip_max_fwd_hdr_create(ctx->pool, 0);
     parse_generic_int_hdr(hdr, ctx->scanner);
 
@@ -1688,5 +1688,5 @@
 {
     pjsip_min_expires_hdr *hdr;
-    hdr = pjsip_min_expires_hdr_create(ctx->pool);
+    hdr = pjsip_min_expires_hdr_create(ctx->pool, 0);
     parse_generic_int_hdr(hdr, ctx->scanner);
     return (pjsip_hdr*)hdr;
@@ -1821,5 +1821,5 @@
     pjsip_generic_string_hdr *hdr;
 
-    hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL);
+    hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL, NULL);
     parse_generic_string_hdr(hdr, ctx->scanner);
     return (pjsip_hdr*)hdr;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_tel_uri.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_tel_uri.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_tel_uri.c	(revision 127)
@@ -65,7 +65,7 @@
 static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri* );
 static void *tel_uri_get_uri( pjsip_tel_uri* );
-static int tel_uri_print( pjsip_uri_context_e context,
-			  const pjsip_tel_uri *url, 
-			  char *buf, pj_size_t size);
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+				 const pjsip_tel_uri *url, 
+				 char *buf, pj_size_t size);
 static int tel_uri_cmp( pjsip_uri_context_e context,
 			const pjsip_tel_uri *url1, const pjsip_tel_uri *url2);
@@ -165,7 +165,7 @@
 
 /* Print tel: URI */
-static int tel_uri_print( pjsip_uri_context_e context,
-			  const pjsip_tel_uri *uri, 
-			  char *buf, pj_size_t size)
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+				 const pjsip_tel_uri *uri, 
+				 char *buf, pj_size_t size)
 {
     int printed;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 127)
@@ -62,6 +62,4 @@
 	PJSIP_MOD_PRIORITY_TSX_LAYER,	/* Priority.		    */
 	NULL,				/* User_data.		    */
-	0,				/* Methods count.	    */
-	{ NULL },			/* Array of methods.	    */
 	mod_tsx_layer_load,		/* load().		    */
 	mod_tsx_layer_start,		/* start()		    */
@@ -508,14 +506,17 @@
 
     /* Check if no transaction with the same key exists. */
-    if (pj_hash_get( mod_tsx_layer.htable, &tsx->transaction_key.ptr,
-		     tsx->transaction_key.slen) != NULL)
-    {
-	pj_mutex_unlock(mod_tsx_layer.mutex);
-	return PJ_EEXISTS;
-    }
+    PJ_ASSERT_ON_FAIL(pj_hash_get( mod_tsx_layer.htable, 
+				   &tsx->transaction_key.ptr,
+				   tsx->transaction_key.slen, 
+				   &tsx->hashed_key) == NULL,
+			{
+			    pj_mutex_unlock(mod_tsx_layer.mutex);
+			    return PJ_EEXISTS;
+			}
+		      );
 
     /* Register the transaction to the hash table. */
     pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr,
-		 tsx->transaction_key.slen, tsx);
+		 tsx->transaction_key.slen, tsx->hashed_key, tsx);
 
     /* Unlock mutex. */
@@ -539,5 +540,5 @@
     /* Register the transaction to the hash table. */
     pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
-		 tsx->transaction_key.slen, NULL);
+		 tsx->transaction_key.slen, tsx->hashed_key, NULL);
 
     /* Unlock mutex. */
@@ -555,5 +556,5 @@
 
     pj_mutex_lock(mod_tsx_layer.mutex);
-    tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen );
+    tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen, NULL );
     pj_mutex_unlock(mod_tsx_layer.mutex);
 
@@ -649,5 +650,5 @@
     pj_mutex_lock( mod_tsx_layer.mutex );
 
-    tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+    tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
 
     if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
@@ -690,5 +691,5 @@
     pj_mutex_lock( mod_tsx_layer.mutex );
 
-    tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+    tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
 
     if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
@@ -1036,4 +1037,8 @@
 			 &via->branch_param);
 
+    /* Calculate hashed key value. */
+    tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+				   tsx->transaction_key.slen);
+
     PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
 	       tsx->transaction_key.ptr));
@@ -1141,4 +1146,8 @@
     }
 
+    /* Calculate hashed key value. */
+    tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+				   tsx->transaction_key.slen);
+
     /* Duplicate branch parameter for transaction. */
     branch = &rdata->msg_info.via->branch_param;
@@ -1179,4 +1188,7 @@
 	return status;
     }
+
+    /* Put this transaction in rdata's mod_data. */
+    rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx;
 
     /* Unlock transaction and return. */
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 127)
@@ -44,20 +44,18 @@
 static pjsip_module mod_msg_print = 
 {
-    NULL, NULL,				/* prev and next	*/
-    { "mod-msg-print", 13},		/* Name.		*/
-    -1,					/* Id			*/
-    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,	/* Priority		*/
-    NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
-    NULL,				/* load()		*/
-    NULL,				/* start()		*/
-    NULL,				/* stop()		*/
-    NULL,				/* unload()		*/
-    NULL,				/* on_rx_request()	*/
-    NULL,				/* on_rx_response()	*/
-    &mod_on_tx_msg,			/* on_tx_request()	*/
-    &mod_on_tx_msg,			/* on_tx_response()	*/
-    NULL,				/* on_tsx_state()	*/
+    NULL, NULL,				/* prev and next		    */
+    { "mod-msg-print", 13},		/* Name.			    */
+    -1,					/* Id				    */
+    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,	/* Priority			    */
+    NULL,				/* User data.			    */
+    NULL,				/* load()			    */
+    NULL,				/* start()			    */
+    NULL,				/* stop()			    */
+    NULL,				/* unload()			    */
+    NULL,				/* on_rx_request()		    */
+    NULL,				/* on_rx_response()		    */
+    &mod_on_tx_msg,			/* on_tx_request()		    */
+    &mod_on_tx_msg,			/* on_tx_response()		    */
+    NULL,				/* on_tsx_state()		    */
 };
 
@@ -349,5 +347,5 @@
 
     if (tdata==NULL || tdata->msg==NULL)
-	return "INVALID MSG";
+	return "NULL";
 
     if (tdata->info)
@@ -590,5 +588,5 @@
     key_len = sizeof(tp->key.type) + tp->addr_len;
     pj_lock_acquire(mgr->lock);
-    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, tp);
+    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, tp);
     pj_lock_release(mgr->lock);
 
@@ -618,5 +616,5 @@
      */
     key_len = sizeof(tp->key.type) + tp->addr_len;
-    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, NULL);
+    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, NULL);
 
     pj_lock_release(mgr->lock);
@@ -879,5 +877,6 @@
 
 	/* Perform basic header checking. */
-	if (rdata->msg_info.cid->id.ptr == NULL || 
+	if (rdata->msg_info.cid == NULL ||
+	    rdata->msg_info.cid->id.slen == 0 || 
 	    rdata->msg_info.from == NULL || 
 	    rdata->msg_info.to == NULL || 
@@ -962,5 +961,5 @@
     pj_memcpy(&key.addr, remote, addr_len);
 
-    transport = pj_hash_get(mgr->table, &key, key_len);
+    transport = pj_hash_get(mgr->table, &key, key_len, NULL);
     if (transport == NULL) {
 	unsigned flag = pjsip_transport_get_flag_from_type(type);
@@ -975,5 +974,5 @@
 	    pj_memset(addr, 0, sizeof(pj_sockaddr_in));
 	    key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
-	    transport = pj_hash_get(mgr->table, &key, key_len);
+	    transport = pj_hash_get(mgr->table, &key, key_len, NULL);
 	}
 	/* For datagram INET transports, try lookup with zero address.
@@ -988,5 +987,5 @@
 
 	    key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
-	    transport = pj_hash_get(mgr->table, &key, key_len);
+	    transport = pj_hash_get(mgr->table, &key, key_len, NULL);
 	}
     }
Index: /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 127)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 127)
@@ -0,0 +1,674 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/os.h>
+#include <pj/hash.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+
+
+#define THIS_FILE    "sip_ua_layer.c"
+
+/*
+ * Static prototypes.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt);
+static pj_status_t mod_ua_unload(void);
+static pj_bool_t   mod_ua_on_rx_request(pjsip_rx_data *rdata);
+static pj_bool_t   mod_ua_on_rx_response(pjsip_rx_data *rdata);
+static void	   mod_ua_on_tsx_state(pjsip_transaction*, pjsip_event*);
+
+
+extern long pjsip_dlg_lock_tls_id;	/* defined in sip_dialog.c */
+
+/* This struct is used to represent list of dialog inside a dialog set.
+ * We don't want to use pjsip_dialog for this purpose, to save some
+ * memory (about 100 bytes per dialog set).
+ */
+struct dlg_set_head
+{
+    PJ_DECL_LIST_MEMBER(pjsip_dialog);
+};
+
+/* This struct represents a dialog set.
+ * This is the value that will be put in the UA's hash table.
+ */
+struct dlg_set
+{
+    /* To put this node in free dlg_set nodes in UA. */
+    PJ_DECL_LIST_MEMBER(struct dlg_set);
+
+    /* This is the buffer to store this entry in the hash table. */
+    char ht_entry[PJ_HASH_ENTRY_SIZE];
+
+    /* List of dialog in this dialog set. */
+    struct dlg_set_head  dlg_list;
+};
+
+
+/*
+ * Module interface.
+ */
+static struct user_agent
+{
+    pjsip_module	 mod;
+    pj_pool_t		*pool;
+    pjsip_endpoint	*endpt;
+    pj_mutex_t		*mutex;
+    pj_hash_table_t	*dlg_table;
+    pjsip_ua_init_param  param;
+    struct dlg_set	 free_dlgset_nodes;
+
+} mod_ua = 
+{
+  {
+    NULL, NULL,		    /* prev, next.			*/
+    { "mod-ua", 6 },	    /* Name.				*/
+    -1,			    /* Id				*/
+    PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,	/* Priority		*/
+    NULL,		    /* User data.			*/
+    &mod_ua_load,	    /* load()				*/
+    NULL,		    /* start()				*/
+    NULL,		    /* stop()				*/
+    &mod_ua_unload,	    /* unload()				*/
+    &mod_ua_on_rx_request,  /* on_rx_request()			*/
+    &mod_ua_on_rx_response, /* on_rx_response()			*/
+    NULL,		    /* on_tx_request.			*/
+    NULL,		    /* on_tx_response()			*/
+    &mod_ua_on_tsx_state,   /* on_tsx_state()			*/
+  }
+};
+
+/* 
+ * mod_ua_load()
+ *
+ * Called when module is being loaded by endpoint.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt)
+{
+    pj_status_t status;
+
+    /* Initialize the user agent. */
+    mod_ua.endpt = endpt;
+    mod_ua.pool = pjsip_endpt_create_pool( endpt, "ua%p", PJSIP_POOL_LEN_UA,
+					   PJSIP_POOL_INC_UA);
+    if (mod_ua.pool == NULL)
+	return PJ_ENOMEM;
+
+    status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
+    if (mod_ua.dlg_table == NULL)
+	return PJ_ENOMEM;
+
+    pj_list_init(&mod_ua.free_dlgset_nodes);
+
+    /* Initialize dialog lock. */
+    status = pj_thread_local_alloc(&pjsip_dlg_lock_tls_id);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
+
+    return PJ_SUCCESS;
+
+}
+
+/*
+ * mod_ua_unload()
+ *
+ * Called when module is being unloaded.
+ */
+static pj_status_t mod_ua_unload(void)
+{
+    pj_thread_local_free(pjsip_dlg_lock_tls_id);
+    pj_mutex_destroy(mod_ua.mutex);
+
+    /* Release pool */
+    if (mod_ua.pool) {
+	pjsip_endpt_release_pool( mod_ua.endpt, mod_ua.pool );
+    }
+    return PJ_SUCCESS;
+}
+
+/*
+ * mod_ua_on_tsx_stats()
+ *
+ * Called on changed on transaction state.
+ */
+static void mod_ua_on_tsx_state( pjsip_transaction *tsx, pjsip_event *e)
+{
+    pjsip_dialog *dlg;
+
+    /* Get the dialog where this transaction belongs. */
+    dlg = tsx->mod_data[mod_ua.mod.id];
+    
+    /* Must have the dialog instance! */
+    PJ_ASSERT_ON_FAIL(dlg != NULL, return);
+
+    /* Hand over the event to the dialog. */
+    pjsip_dlg_on_tsx_state(dlg, tsx, e);
+}
+
+
+/*
+ * Init user agent module and register it to the endpoint.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_init( pjsip_endpoint *endpt,
+				   const pjsip_ua_init_param *prm)
+{
+    pj_status_t status;
+
+    /* Check if module already registered. */
+    PJ_ASSERT_RETURN(mod_ua.mod.id == -1, PJ_EINVALIDOP);
+
+    /* Copy param, if exists. */
+    if (prm)
+	pj_memcpy(&mod_ua.param, prm, sizeof(pjsip_ua_init_param));
+
+    /* Register the module. */
+    status = pjsip_endpt_register_module(endpt, &mod_ua.mod);
+
+    return status;
+}
+
+/*
+ * Get the instance of the user agent.
+ *
+ */
+PJ_DEF(pjsip_user_agent*) pjsip_ua_instance(void)
+{
+    return &mod_ua.mod;
+}
+
+
+/*
+ * Destroy the user agent layer.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_destroy(void)
+{
+    /* Check if module already destroyed. */
+    PJ_ASSERT_RETURN(mod_ua.mod.id != -1, PJ_EINVALIDOP);
+
+    return pjsip_endpt_unregister_module(mod_ua.endpt, &mod_ua.mod);
+}
+
+
+
+/*
+ * Create key to identify dialog set.
+ */
+PJ_DEF(void) pjsip_ua_create_dlg_set_key( pj_pool_t *pool,
+					  pj_str_t *set_key,
+					  const pj_str_t *call_id,
+					  const pj_str_t *local_tag)
+{
+    PJ_ASSERT_ON_FAIL(pool && set_key && call_id && local_tag, return;);
+
+    set_key->slen = call_id->slen + local_tag->slen + 1;
+    set_key->ptr = pj_pool_alloc(pool, set_key->slen);
+    pj_assert(set_key->ptr != NULL);
+
+    pj_memcpy(set_key->ptr, call_id->ptr, call_id->slen);
+    set_key->ptr[call_id->slen] = '$';
+    pj_memcpy(set_key->ptr + call_id->slen + 1, 
+	      local_tag->ptr, local_tag->slen);
+}
+
+/*
+ * Acquire one dlg_set node to be put in the hash table.
+ * This will first look in the free nodes list, then allocate
+ * a new one from UA's pool when one is not available.
+ */
+static struct dlg_set *alloc_dlgset_node(void)
+{
+    struct dlg_set *set;
+
+    if (!pj_list_empty(&mod_ua.free_dlgset_nodes)) {
+	set = mod_ua.free_dlgset_nodes.next;
+	pj_list_erase(set);
+	return set;
+    } else {
+	set = pj_pool_alloc(mod_ua.pool, sizeof(struct dlg_set));
+	return set;
+    }
+}
+
+/*
+ * Register new dialog. Called by pjsip_dlg_create_uac() and
+ * pjsip_dlg_create_uas();
+ */
+PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+					   pjsip_dialog *dlg )
+{
+    /* Sanity check. */
+    PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+    /* For all dialogs, local tag (inc hash) must has been initialized. */
+    PJ_ASSERT_RETURN(dlg->local.info && dlg->local.info->tag.slen &&
+		     dlg->local.tag_hval != 0, PJ_EBUG);
+
+    /* For UAS dialog, remote tag (inc hash) must have been initialized. */
+    PJ_ASSERT_RETURN(dlg->role==PJSIP_ROLE_UAC ||
+		     (dlg->role==PJSIP_ROLE_UAS && dlg->remote.info->tag.slen
+		      && dlg->remote.tag_hval != 0), PJ_EBUG);
+
+    /* Lock the user agent. */
+    pj_mutex_lock(mod_ua.mutex);
+
+    /* For UAC, check if there is existing dialog in the same set. */
+    if (dlg->role == PJSIP_ROLE_UAC) {
+	struct dlg_set *dlg_set;
+
+	dlg_set = pj_hash_get( mod_ua.dlg_table, dlg->local.info->tag.ptr, 
+			       dlg->local.info->tag.slen,
+			       &dlg->local.tag_hval);
+
+	if (dlg_set) {
+	    /* This is NOT the first dialog in the dialog set. 
+	     * Just add this dialog in the list.
+	     */
+	    pj_assert(dlg_set->dlg_list.next != (void*)&dlg_set->dlg_list);
+	    pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+	    dlg->dlg_set = dlg_set;
+
+	} else {
+	    /* This is the first dialog in the dialog set. 
+	     * Create the dialog set and add this dialog to it.
+	     */
+	    dlg_set = alloc_dlgset_node();
+	    pj_list_init(&dlg_set->dlg_list);
+	    pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+	    dlg->dlg_set = dlg_set;
+
+	    /* Register the dialog set in the hash table. */
+	    pj_hash_set_np(mod_ua.dlg_table, 
+			   dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+			   dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+	}
+
+    } else {
+	/* For UAS, create the dialog set with a single dialog as member. */
+	struct dlg_set *dlg_set;
+
+	dlg_set = alloc_dlgset_node();
+	pj_list_init(&dlg_set->dlg_list);
+	pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+	dlg->dlg_set = dlg_set;
+
+	pj_hash_set_np(mod_ua.dlg_table, 
+		       dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+		       dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+    }
+
+    /* Unlock user agent. */
+    pj_mutex_unlock(mod_ua.mutex);
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_ua_unregister_dlg( pjsip_user_agent *ua,
+					     pjsip_dialog *dlg )
+{
+    struct dlg_set *dlg_set;
+    pjsip_dialog *d;
+
+    /* Sanity-check arguments. */
+    PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+    /* Check that dialog has been registered. */
+    PJ_ASSERT_RETURN(dlg->dlg_set, PJ_EINVALIDOP);
+
+    /* Lock user agent. */
+    pj_mutex_lock(mod_ua.mutex);
+
+    /* Find this dialog from the dialog set. */
+    dlg_set = dlg->dlg_set;
+    d = dlg_set->dlg_list.next;
+    while (d != (pjsip_dialog*)&dlg_set->dlg_list && d != dlg) {
+	d = d->next;
+    }
+
+    if (d != dlg) {
+	pj_assert(!"Dialog is not registered!");
+	pj_mutex_unlock(mod_ua.mutex);
+	return PJ_EINVALIDOP;
+    }
+
+    /* Remove this dialog from the list. */
+    pj_list_erase(dlg);
+
+    /* If dialog list is empty, remove the dialog set from the hash table. */
+    if (pj_list_empty(&dlg_set->dlg_list)) {
+	pj_hash_set(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
+		    dlg->local.info->tag.slen, dlg->local.tag_hval, NULL);
+
+	/* Return dlg_set to free nodes. */
+	pj_list_push_back(&mod_ua.free_dlgset_nodes, dlg_set);
+    }
+
+    /* Unlock user agent. */
+    pj_mutex_unlock(mod_ua.mutex);
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata )
+{
+    return rdata->endpt_info.mod_data[mod_ua.mod.id];
+}
+
+PJ_DEF(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx )
+{
+    return tsx->mod_data[mod_ua.mod.id];
+}
+
+
+/*
+ * Find the first dialog in dialog set in hash table for an incoming message.
+ */
+static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata )
+{
+    /* CANCEL message doesn't have To tag, so we must lookup the dialog
+     * by finding the INVITE UAS transaction being cancelled.
+     */
+    if (rdata->msg_info.cseq->method.id == PJSIP_CANCEL_METHOD) {
+
+	pjsip_dialog *dlg;
+
+	/* Create key for the rdata, but this time, use INVITE as the
+	 * method.
+	 */
+	pj_str_t key;
+	pjsip_role_e role;
+	pjsip_transaction *tsx;
+
+	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+	    role = PJSIP_ROLE_UAS;
+	else
+	    role = PJSIP_ROLE_UAC;
+
+	pjsip_tsx_create_key(rdata->tp_info.pool, &key, role, 
+			     &pjsip_invite_method, rdata);
+
+	/* Lookup the INVITE transaction */
+	tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+
+	/* We should find the dialog attached to the INVITE transaction */
+	if (tsx) {
+	    dlg = tsx->mod_data[mod_ua.mod.id];
+	    pj_mutex_unlock(tsx->mutex);
+
+	    return dlg->dlg_set;
+
+	} else {
+	    return NULL;
+	}
+
+
+    } else {
+	pj_str_t *tag;
+	struct dlg_set *dlg_set;
+
+	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+	    tag = &rdata->msg_info.to->tag;
+	else
+	    tag = &rdata->msg_info.from->tag;
+
+	/* Lookup the dialog set. */
+	dlg_set = pj_hash_get(mod_ua.dlg_table, tag->ptr, tag->slen, NULL);
+	return dlg_set;
+    }
+}
+
+/* On received requests. */
+static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
+{
+    struct dlg_set *dlg_set;
+    pj_str_t *from_tag;
+    pjsip_dialog *dlg;
+
+    /* Lock user agent before looking up the dialog hash table. */
+    pj_mutex_lock(mod_ua.mutex);
+
+    /* Lookup the dialog set, based on the To tag header. */
+    dlg_set = find_dlg_set_for_msg(rdata);
+
+    /* Bail out if dialog is not found. */
+    if (dlg_set == NULL) {
+	/* Not ours. */
+	pj_mutex_unlock(mod_ua.mutex);
+	return PJ_FALSE;
+    }
+
+    /* Dialog set has been found.
+     * Find the dialog in the dialog set based on the content of the From tag.
+     */
+    from_tag = &rdata->msg_info.from->tag;
+    dlg = dlg_set->dlg_list.next;
+    while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+	
+	if (pj_strcmp(&dlg->remote.info->tag, from_tag) == 0)
+	    break;
+
+	dlg = dlg->next;
+    }
+
+    /* Dialog MUST be found! */
+    if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+	/* Not found. Mulfunction UAC? */
+	pj_mutex_unlock(mod_ua.mutex);
+	pjsip_endpt_respond_stateless(mod_ua.endpt, rdata,
+				      PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, 
+				      NULL, NULL, NULL);
+	return PJ_TRUE;
+    }
+
+    /* Mark the dialog id of the request. */
+    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+    /* Done processing in the UA */
+    pj_mutex_unlock(mod_ua.mutex);
+
+    /* Pass to dialog. */
+    pjsip_dlg_on_rx_request(dlg, rdata);
+
+    /* Report as handled. */
+    return PJ_TRUE;
+}
+
+
+/* On rx response notification.
+ */
+static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
+{
+    pjsip_transaction *tsx;
+    struct dlg_set *dlg_set;
+    pjsip_dialog *dlg = NULL;
+
+    /*
+     * Find the dialog instance for the response.
+     * All outgoing dialog requests are sent statefully, which means
+     * there will be an UAC transaction associated with this response,
+     * and the dialog instance will be recorded in that transaction.
+     *
+     * But even when transaction is found, there is possibility that
+     * the response is a forked response.
+     */
+
+    /* Check if transaction is present. */
+    tsx = pjsip_rdata_get_tsx(rdata);
+    if (!tsx) {
+	/* Check if dialog is present in the transaction. */
+	dlg = pjsip_tsx_get_dlg(tsx);
+	if (!dlg)
+	    return PJ_FALSE;
+
+	/* Get the dialog set. */
+	dlg_set = dlg->dlg_set;
+
+	/* Even if transaction is found and (candidate) dialog has been 
+	 * identified, it's possible that the request has forked.
+	 */
+
+    } else {
+	/* Transaction is not present.
+	 * Check if this is a 2xx/OK response to INVITE, which in this
+	 * case the response will be handled directly by the
+	 * dialog.
+	 */
+	pjsip_cseq_hdr *cseq_hdr = rdata->msg_info.cseq;
+
+	if (cseq_hdr->method.id != PJSIP_INVITE_METHOD ||
+	    rdata->msg_info.msg->line.status.code / 100 != 2)
+	{
+	    /* Not a 2xx response to INVITE.
+	     * This must be some stateless response sent by other modules,
+	     * or a very late response.
+	     */
+	    return PJ_FALSE;
+	}
+
+	/* Lock user agent before accessing the hash table. */
+	pj_mutex_lock(mod_ua.mutex);
+
+	/* Get the dialog set. */
+	dlg_set = pj_hash_get(mod_ua.dlg_table, 
+			      rdata->msg_info.from->tag.ptr,
+			      rdata->msg_info.from->tag.slen,
+			      NULL);
+
+	/* Done with accessing the hash table. */
+	pj_mutex_unlock(mod_ua.mutex);
+
+	if (!dlg_set) {
+	    /* Strayed 2xx response!! */
+	    PJ_LOG(4,(THIS_FILE, 
+		      "Received strayed 2xx response (no dialog is found)"
+		      " from %s:%d: %s",
+		      rdata->pkt_info.src_name, rdata->pkt_info.src_port,
+		      pjsip_rx_data_get_info(rdata)));
+
+	    return PJ_TRUE;
+	}
+    }
+
+    /* At this point, we must have the dialog set, and the dialog set
+     * must have a dialog in the list.
+     */
+    pj_assert(dlg_set && !pj_list_empty(&dlg_set->dlg_list));
+
+    /* Check for forked response. 
+     * Request will fork only for the initial INVITE request.
+     */
+    if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
+	rdata->msg_info.cseq->cseq == dlg_set->dlg_list.next->local.first_cseq)
+    {
+	pj_str_t *to_tag = &rdata->msg_info.to->tag;
+
+	/* Must hold UA mutex before accessing dialog set. */
+	pj_mutex_lock(mod_ua.mutex);
+
+	dlg = dlg_set->dlg_list.next;
+	while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+
+	    /* If there is dialog with no remote tag (i.e. dialog has not
+	     * been established yet), then send this response to that
+	     * dialog.
+	     */
+	    if (dlg->remote.info->tag.slen == 0)
+		break;
+
+	    /* Otherwise find the one with matching To tag. */
+	    if (pj_strcmp(to_tag, &dlg->remote.info->tag) == 0)
+		break;
+
+	    dlg = dlg->next;
+	}
+
+	/* If no dialog with matching remote tag is found, this must be
+	 * a forked response.
+	 */
+	if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+	    /* Report to application about forked condition.
+	     * Application can either create a dialog or ignore the response.
+	     */
+	    if (mod_ua.param.on_dlg_forked)
+		dlg = (*mod_ua.param.on_dlg_forked)(dlg_set->dlg_list.next, 
+						    rdata);
+	    else
+		dlg = NULL;
+
+	    /* Ignore this response if application doesn't want to
+	     * create a dialog.
+	     */
+	    if (dlg == NULL) {
+		pj_mutex_unlock(mod_ua.mutex);
+
+		PJ_LOG(4,(THIS_FILE, 
+			  "Unhandled forked %s from %s:%d",
+			  pjsip_rx_data_get_info(rdata),
+			  rdata->pkt_info.src_name, rdata->pkt_info.src_port));
+
+		return PJ_TRUE;
+	    }
+	}
+
+	/* Done with the dialog set. */
+	pj_mutex_unlock(mod_ua.mutex);
+
+    } else {
+	/* Either this is a non-INVITE response, or subsequent INVITE
+	 * within dialog. The dialog should have been identified when
+	 * the transaction was found.
+	 */
+	pj_assert(tsx != NULL);
+	pj_assert(dlg != NULL);
+    }
+
+    /* The dialog must have been found. */
+    pj_assert(dlg != NULL);
+
+    /* Put the dialog instance in the rdata. */
+    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+    /* Pass the response to the dialog. */
+    pjsip_dlg_on_rx_response(dlg, rdata);
+
+    /* Done. */
+    return PJ_TRUE;
+}
+
+
Index: /pjproject/trunk/pjsip/src/pjsip/sip_uri.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_uri.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_uri.c	(revision 127)
@@ -141,13 +141,13 @@
 static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 
 					       const pjsip_name_addr *rhs);
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
-				  const pjsip_name_addr *name, 
-				  char *buf, pj_size_t size);
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+					const pjsip_name_addr *name, 
+					char *buf, pj_size_t size);
 static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
 				     const pjsip_name_addr *naddr1,
 				     const pjsip_name_addr *naddr2);
-static int pjsip_url_print(  pjsip_uri_context_e context,
-			     const pjsip_sip_uri *url, 
-			     char *buf, pj_size_t size);
+static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
+				    const pjsip_sip_uri *url, 
+				    char *buf, pj_size_t size);
 static int pjsip_url_compare( pjsip_uri_context_e context,
 			      const pjsip_sip_uri *url1, 
@@ -205,5 +205,5 @@
 }
 
-PJ_DEF(void) pjsip_url_init(pjsip_sip_uri *url, int secure)
+PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, int secure)
 {
     pj_memset(url, 0, sizeof(*url));
@@ -214,14 +214,14 @@
 }
 
-PJ_DEF(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure )
+PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure )
 {
     pjsip_sip_uri *url = pj_pool_alloc(pool, sizeof(pjsip_sip_uri));
-    pjsip_url_init(url, secure);
+    pjsip_sip_uri_init(url, secure);
     return url;
 }
 
-static int pjsip_url_print(  pjsip_uri_context_e context,
-			     const pjsip_sip_uri *url, 
-			     char *buf, pj_size_t size)
+static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
+				    const pjsip_sip_uri *url, 
+				    char *buf, pj_size_t size)
 {
     int printed;
@@ -466,6 +466,6 @@
 
 
-PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url, 
-			      const pjsip_sip_uri *rhs)
+PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url, 
+				  const pjsip_sip_uri *rhs)
 {
     pj_strdup( pool, &url->user, &rhs->user);
@@ -489,6 +489,6 @@
 	return NULL;
 
-    pjsip_url_init(url, IS_SIPS(rhs));
-    pjsip_url_assign(pool, url, rhs);
+    pjsip_sip_uri_init(url, IS_SIPS(rhs));
+    pjsip_sip_uri_assign(pool, url, rhs);
     return url;
 }
@@ -514,7 +514,7 @@
 }
 
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
-				  const pjsip_name_addr *name, 
-				  char *buf, pj_size_t size)
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+					const pjsip_name_addr *name, 
+					char *buf, pj_size_t size)
 {
     int printed;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_util.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 127)
@@ -129,7 +129,7 @@
 	    pjsip_generic_string_hdr *hdr;
 
-	    hdr = pjsip_generic_string_hdr_create_with_text(tdata->pool, 
-							    &hparam->name,
-							    &hparam->value);
+	    hdr = pjsip_generic_string_hdr_create(tdata->pool, 
+						  &hparam->name,
+						  &hparam->value);
 	    pjsip_msg_add_hdr(msg, (pjsip_hdr*)hdr);
 	    hparam = hparam->next;
@@ -303,7 +303,7 @@
 	target = pjsip_uri_clone(tdata->pool, param_target);
 	from = pjsip_hdr_clone(tdata->pool, param_from);
-	pjsip_fromto_set_from(from);
+	pjsip_fromto_hdr_set_from(from);
 	to = pjsip_hdr_clone(tdata->pool, param_to);
-	pjsip_fromto_set_to(to);
+	pjsip_fromto_hdr_set_to(to);
 	if (param_contact)
 	    contact = pjsip_hdr_clone(tdata->pool, param_contact);
Index: /pjproject/trunk/pjsip/src/test-pjsip/dlg_core_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/dlg_core_test.c	(revision 127)
+++ /pjproject/trunk/pjsip/src/test-pjsip/dlg_core_test.c	(revision 127)
@@ -0,0 +1,22 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include "test.h"
+#include <pjsip.h>
+
Index: /pjproject/trunk/pjsip/src/test-pjsip/msg_logger.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/msg_logger.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/msg_logger.c	(revision 127)
@@ -18,5 +18,5 @@
  */
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -65,6 +65,4 @@
     PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
Index: /pjproject/trunk/pjsip/src/test-pjsip/msg_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/msg_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/msg_test.c	(revision 127)
@@ -18,5 +18,5 @@
  */
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -349,5 +349,5 @@
     /* "INVITE sip:user@foo SIP/2.0\n" */
     pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     msg->line.req.uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "user");
@@ -361,5 +361,5 @@
     fromto->uri = (pjsip_uri*)name_addr;
     pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "joe.user");
@@ -372,5 +372,5 @@
     fromto->uri = (pjsip_uri*)name_addr;
     pj_strdup2(pool, &name_addr->display, "Fellow User");
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "user");
@@ -400,5 +400,5 @@
     name_addr = pjsip_name_addr_create(pool);
     contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "joe");
@@ -411,5 +411,5 @@
     name_addr = pjsip_name_addr_create(pool);
     contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "user");
@@ -421,5 +421,5 @@
     name_addr = pjsip_name_addr_create(pool);
     contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->user, "user2");
@@ -436,5 +436,5 @@
     routing = pjsip_route_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     routing->name_addr.uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
@@ -444,5 +444,5 @@
     routing = pjsip_route_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     routing->name_addr.uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->host, "server10.biloxi.com");
@@ -452,5 +452,5 @@
     routing = pjsip_rr_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     routing->name_addr.uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->host, "server10.biloxi.com");
@@ -460,5 +460,5 @@
     routing = pjsip_rr_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     routing->name_addr.uri = (pjsip_uri*)url;
     pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
@@ -498,5 +498,5 @@
     str.ptr = "Organization";
     str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
+    generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
     generic->hvalue.ptr = NULL;
@@ -506,5 +506,5 @@
     str.ptr = "Max-Forwards";
     str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
+    generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
     str.ptr = "70";
@@ -515,5 +515,5 @@
     str.ptr = "X-Header";
     str.slen = 8;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
+    generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
     str.ptr = NULL;
@@ -524,5 +524,5 @@
     str.ptr = "P-Associated-URI";
     str.slen = 16;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
+    generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
     str.ptr = NULL;
@@ -539,5 +539,5 @@
     pjsip_name_addr *name_addr;
     pjsip_sip_uri *url;
-    pjsip_max_forwards_hdr *max_fwd;
+    pjsip_max_fwd_hdr *max_fwd;
     pjsip_to_hdr *to;
     pjsip_from_hdr *from;
@@ -582,5 +582,5 @@
     route = pjsip_route_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
-    url = pjsip_url_create(pool, PJ_FALSE);
+    url = pjsip_sip_uri_create(pool, PJ_FALSE);
     route->name_addr.uri = (pjsip_uri*)url;
     url->host = pj_str("proxy.sipprovider.com");
@@ -589,5 +589,5 @@
     route = pjsip_route_hdr_create(pool);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
-    url = pjsip_url_create(pool, PJ_FALSE);
+    url = pjsip_sip_uri_create(pool, PJ_FALSE);
     route->name_addr.uri = (pjsip_uri*)url;
     url->host = pj_str("proxy.supersip.com");
@@ -595,7 +595,6 @@
 
     //"Max-Forwards: 70\r\n"
-    max_fwd = pjsip_max_forwards_hdr_create(pool);
+    max_fwd = pjsip_max_fwd_hdr_create(pool, 70);
     pjsip_msg_add_hdr(msg, (pjsip_hdr*)max_fwd);
-    max_fwd->ivalue = 70;
 
     //"To: Bob <sip:bob@biloxi.com>;tag=a6c85cf\r\n"
@@ -605,5 +604,5 @@
     name_addr->display = pj_str("Bob");
     to->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, PJ_FALSE);
+    url = pjsip_sip_uri_create(pool, PJ_FALSE);
     name_addr->uri = (pjsip_uri*)url;
     url->user = pj_str("bob");
@@ -617,5 +616,5 @@
     name_addr->display = pj_str("Alice");
     from->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, PJ_FALSE);
+    url = pjsip_sip_uri_create(pool, PJ_FALSE);
     name_addr->uri = (pjsip_uri*)url;
     url->user = pj_str("alice");
@@ -639,5 +638,5 @@
     name_addr = pjsip_name_addr_create(pool);
     contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, PJ_TRUE);
+    url = pjsip_sip_uri_create(pool, PJ_TRUE);
     name_addr->uri = (pjsip_uri*)url;
     url->user = pj_str("bob");
Index: /pjproject/trunk/pjsip/src/test-pjsip/test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/test.c	(revision 127)
@@ -21,5 +21,5 @@
 #include "test.h"
 #include <pjlib.h>
-#include <pjsip_core.h>
+#include <pjsip.h>
 
 #define THIS_FILE   "test.c"
Index: /pjproject/trunk/pjsip/src/test-pjsip/transport_loop_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/transport_loop_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/transport_loop_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
Index: /pjproject/trunk/pjsip/src/test-pjsip/transport_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/transport_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/transport_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -102,6 +102,4 @@
     PJSIP_MOD_PRIORITY_TSX_LAYER-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
@@ -306,6 +304,4 @@
     PJSIP_MOD_PRIORITY_TSX_LAYER-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
Index: /pjproject/trunk/pjsip/src/test-pjsip/transport_udp_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/transport_udp_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/transport_udp_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
Index: /pjproject/trunk/pjsip/src/test-pjsip/tsx_basic_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/tsx_basic_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/tsx_basic_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
Index: /pjproject/trunk/pjsip/src/test-pjsip/tsx_uac_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/tsx_uac_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/tsx_uac_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -104,6 +104,4 @@
     PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
@@ -125,6 +123,4 @@
     PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
Index: /pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -143,6 +143,4 @@
     PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
@@ -164,6 +162,4 @@
     PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
     NULL,				/* User data.		*/
-    0,					/* Number of methods supported (=0). */
-    { 0 },				/* Array of methods (none) */
     NULL,				/* load()		*/
     NULL,				/* start()		*/
Index: /pjproject/trunk/pjsip/src/test-pjsip/txdata_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/txdata_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/txdata_test.c	(revision 127)
@@ -19,5 +19,5 @@
 
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
Index: /pjproject/trunk/pjsip/src/test-pjsip/uri_test.c
===================================================================
--- /pjproject/trunk/pjsip/src/test-pjsip/uri_test.c	(revision 126)
+++ /pjproject/trunk/pjsip/src/test-pjsip/uri_test.c	(revision 127)
@@ -18,5 +18,5 @@
  */
 #include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
 #include <pjlib.h>
 
@@ -318,5 +318,5 @@
 {
     /* "sip:localhost" */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2(pool, &url->host, "localhost");
@@ -327,5 +327,5 @@
 {
     /* "sip:user@localhost" */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2( pool, &url->user, "user");
@@ -338,5 +338,5 @@
 {
     /* "sip:user:password@localhost:5060" */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2( pool, &url->user, "user");
@@ -351,5 +351,5 @@
 {
     /* Like: "sip:localhost:5060", but without the port. */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2(pool, &url->host, "localhost");
@@ -360,5 +360,5 @@
 {
     /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2(pool, &url->host, "localhost");
@@ -387,5 +387,5 @@
        "?Subject=Hello%20There&Server=SIP%20Server" 
      */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
 
     pj_strdup2(pool, &url->host, "localhost");
@@ -406,5 +406,5 @@
 {
     /* "sips:localhost" */
-    pjsip_sip_uri *url = pjsip_url_create(pool, 1);
+    pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 1);
 
     pj_strdup2(pool, &url->host, "localhost");
@@ -418,5 +418,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -431,5 +431,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 1);
+    url = pjsip_sip_uri_create(pool, 1);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -445,5 +445,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -461,5 +461,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -475,5 +475,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -489,5 +489,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -501,5 +501,5 @@
     /* "sip:localhost;pvalue=\"hello world\"" */
     pjsip_sip_uri *url;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     pj_strdup2(pool, &url->host, "localhost");
     //pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
@@ -514,5 +514,5 @@
     pjsip_sip_uri *url;
 
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     name_addr->uri = (pjsip_uri*) url;
 
@@ -529,5 +529,5 @@
     /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
     pjsip_sip_uri *url;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
     return (pjsip_uri*)url;
@@ -538,5 +538,5 @@
     /* "sip:" USER_CHAR ":" PASS_CHAR "@host" */
     pjsip_sip_uri *url;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     pj_strdup2(pool, &url->user, USER_CHAR);
     pj_strdup2(pool, &url->passwd, PASS_CHAR);
@@ -549,5 +549,5 @@
     /* "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21;lr;other=1;transport=sctp;other2" */
     pjsip_sip_uri *url;
-    url = pjsip_url_create(pool, 0);
+    url = pjsip_sip_uri_create(pool, 0);
     pj_strdup2(pool, &url->host, "host");
     pj_strdup2(pool, &url->user_param, "ip");
Index: /pjproject/trunk/svn_add
===================================================================
--- /pjproject/trunk/svn_add	(revision 127)
+++ /pjproject/trunk/svn_add	(revision 127)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+svn add $1
+svn pset svn:keywords id $1
+svn pset svn:eol-style native $1
+
