Index: pjproject/trunk/pjsip/build/pjsip.dsw
===================================================================
--- pjproject/trunk/pjsip/build/pjsip.dsw	(revision 63)
+++ pjproject/trunk/pjsip/build/pjsip.dsw	(revision 64)
@@ -58,16 +58,4 @@
 ###############################################################################
 
-Project: "test_pjsip"=.\test_pjsip.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
 Project: "pjsip_ua"=.\pjsip_ua.dsp - Package Owner=<4>
 
@@ -109,4 +97,22 @@
 ###############################################################################
 
+Project: "test_pjsip"=.\test_pjsip.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name pjlib
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjsip_core
+    End Project Dependency
+}}}
+
+###############################################################################
+
 Global:
 
Index: pjproject/trunk/pjsip/build/pjsip_core.dsp
===================================================================
--- pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 63)
+++ pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 64)
@@ -104,5 +104,5 @@
 # Begin Source File
 
-SOURCE=..\src\pjsip\sip_misc.c
+SOURCE=..\src\pjsip\sip_errno.c
 # End Source File
 # Begin Source File
@@ -133,4 +133,8 @@
 
 SOURCE=..\src\pjsip\sip_uri.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_util.c
 # End Source File
 # End Group
@@ -176,8 +180,4 @@
 # Begin Source File
 
-SOURCE=..\include\pjsip\sip_misc.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\include\pjsip\sip_module.h
 # End Source File
@@ -217,4 +217,8 @@
 
 SOURCE=..\include\pjsip\sip_uri.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_util.h
 # End Source File
 # End Group
Index: pjproject/trunk/pjsip/build/test_pjsip.dsp
===================================================================
--- pjproject/trunk/pjsip/build/test_pjsip.dsp	(revision 63)
+++ pjproject/trunk/pjsip/build/test_pjsip.dsp	(revision 64)
@@ -52,5 +52,5 @@
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 wsock32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-release.exe"
+# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-release.exe"
 
 !ELSEIF  "$(CFG)" == "test_pjsip - Win32 Debug"
@@ -77,5 +77,5 @@
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 wsock32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-debug.exe" /pdbtype:sept
+# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-debug.exe" /pdbtype:sept
 
 !ENDIF 
@@ -94,9 +94,13 @@
 # Begin Source File
 
-SOURCE="..\src\test-pjsip\test_msg.c"
+SOURCE="..\src\test-pjsip\msg.c"
 # End Source File
 # Begin Source File
 
-SOURCE="..\src\test-pjsip\test_uri.c"
+SOURCE="..\src\test-pjsip\test.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\test-pjsip\uri.c"
 # End Source File
 # End Group
Index: pjproject/trunk/pjsip/include/pjsip/print_util.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/print_util.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/print_util.h	(revision 64)
@@ -20,7 +20,10 @@
 #define __PJSIP_PRINT_H__
 
+/* Minimum space left in the buffer */
+#define MIN_SPACE	10
+
 #define copy_advance_check(buf,str)   \
 	do { \
-	    if ((str).slen+10 >= (endbuf-buf)) return -1;	\
+	    if ((str).slen+MIN_SPACE >= (endbuf-buf)) return -1;	\
 	    pj_memcpy(buf, (str).ptr, (str).slen); \
 	    buf += (str).slen; \
@@ -32,5 +35,5 @@
     if (str2->slen) {
 	int printed = len1+str2->slen;
-	if (printed+10 >= (endbuf-buf)) return NULL;
+	if (printed+MIN_SPACE >= (endbuf-buf)) return NULL;
 	pj_memcpy(buf,str1,len1);
 	pj_memcpy(buf+len1, str2->ptr, str2->slen);
@@ -45,5 +48,5 @@
 	    if (str2.slen) { \
 		printed = len1+str2.slen; \
-		if (printed+10 >= (endbuf-buf)) return -1;	\
+		if (printed+MIN_SPACE >= (endbuf-buf)) return -1;	\
 		pj_memcpy(buf,str1,len1); \
 		pj_memcpy(buf+len1, str2.ptr, str2.slen); \
@@ -63,5 +66,5 @@
 	    if (str2.slen) { \
 		printed = len1+str2.slen+2; \
-		if (printed+10 >= (endbuf-buf)) return -1;	\
+		if (printed+MIN_SPACE >= (endbuf-buf)) return -1;	\
 		pj_memcpy(buf,str1,len1); \
 		*(buf+len1)=quotebegin; \
@@ -72,7 +75,33 @@
 	} while (0)
 
+#define copy_advance_pair_escape(buf,str1,len1,str2,unres)	\
+	do { \
+	    if (str2.slen) { \
+		pj_ssize_t esc_len; \
+		if (len1+str2.slen+MIN_SPACE >= (endbuf-buf)) return -1; \
+		pj_memcpy(buf,str1,len1); \
+		buf += len1; \
+		esc_len=pj_strncpy2_escape(buf, &str2, (endbuf-buf), &unres); \
+		if (esc_len < 0) return -1; \
+		buf += esc_len; \
+		if (endbuf-buf < MIN_SPACE) return -1; \
+	    } \
+	} while (0)
+
+
 #define copy_advance_no_check(buf,str)   \
-	pj_memcpy(buf, (str).ptr, (str).slen); \
-	buf += (str).slen;
+	do { \
+	    pj_memcpy(buf, (str).ptr, (str).slen); \
+	    buf += (str).slen; \
+	} while (0)
+
+#define copy_advance_escape(buf,str,unres)    \
+	do { \
+	    pj_ssize_t len = \
+		pj_strncpy2_escape(buf, &(str), (endbuf-buf), &(unres)); \
+	    if (len < 0) return -1; \
+	    buf += len; \
+	    if (endbuf-buf < MIN_SPACE) return -1; \
+	} while (0)
 
 #define copy_advance_pair_no_check(buf,str1,len1,str2)   \
Index: pjproject/trunk/pjsip/include/pjsip/sip_errno.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 64)
@@ -22,8 +22,29 @@
 #include <pj/errno.h>
 
+PJ_BEGIN_DECL
+
+/*
+ * PJSIP error codes occupies 170000 - 219000, and mapped as follows:
+ *  - 170100 - 170799: mapped to SIP status code in response msg.
+ *  - 171000 - 171999: mapped to errors generated from PJSIP core.
+ */
+
+/**
+ * Get error message for the specified error code.
+ *
+ * @param status    The error code.
+ * @param buffer    The buffer where to put the error message.
+ * @param bufsize   Size of the buffer.
+ *
+ * @return	    The error message as NULL terminated string,
+ *                  wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
+				  pj_size_t bufsize);
+
 /**
  * Start of error code relative to PJ_ERRNO_START_USER.
  */
-#define PJSIP_ERRNO_START       (PJ_ERRNO_START_USER+10000)
+#define PJSIP_ERRNO_START       (PJ_ERRNO_START_USER)
 
 /**
@@ -44,5 +65,5 @@
 #define PJSIP_ERRNO_TO_SIP_STATUS(status)               \
          ((status>=PJSIP_ERRNO_FROM_SIP_STATUS(100) &&  \
-           status<PJSIP_ERRNO_FROM_SIP_STATUS(999)) ?   \
+           status<PJSIP_ERRNO_FROM_SIP_STATUS(800)) ?   \
           status-PJSIP_ERRNO_FROM_SIP_STATUS(0) : 599)
 
@@ -51,73 +72,157 @@
  * Start of PJSIP generated error code values.
  */
-#define PJSIP_ERRNO_START_PJSIP (PJSIP_ERRNO_START + 10000)
-
+#define PJSIP_ERRNO_START_PJSIP (PJSIP_ERRNO_START + 1000)
+
+/************************************************************
+ * GENERIC SIP ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * SIP object is busy.
+ */
+#define PJSIP_EBUSY		(PJSIP_ERRNO_START_PJSIP + 1)	/* 171001 */
+/**
+ * @hideinitializer
+ * SIP object with the same type already exists.
+ */
+#define PJSIP_ETYPEEXISTS	(PJSIP_ERRNO_START_PJSIP + 2)	/* 171002 */
+
+
+/************************************************************
+ * MESSAGING ERRORS
+ ***********************************************************/
 /**
  * @hideinitializer
  * Invalid message (syntax error)
  */
-#define PJSIP_EINVALIDMSG       (PJSIP_ERRNO_START_PJSIP + 0)
+#define PJSIP_EINVALIDMSG       (PJSIP_ERRNO_START_PJSIP + 20)	/* 171020 */
+/**
+ * @hideinitializer
+ * Unsupported URL scheme.
+ */
+#define PJSIP_EINVALIDSCHEME    (PJSIP_ERRNO_START_PJSIP + 21)	/* 171021 */
+/**
+ * @hideinitializer
+ * Message too long. See also PJSIP_ERXOVERFLOW.
+ */
+#define PJSIP_EMSGTOOLONG	(PJSIP_ERRNO_START_PJSIP + 22)	/* 171022 */
+/**
+ * @hideinitializer
+ * Message not completely received.
+ */
+#define PJSIP_EPARTIALMSG       (PJSIP_ERRNO_START_PJSIP + 23)	/* 171023 */
 /**
  * @hideinitializer
  * Missing required header(s).
  */
-#define PJSIP_EMISSINGHDR       (PJSIP_ERRNO_START_PJSIP + 1)
-/**
- * @hideinitializer
- * Unsupported URL scheme.
- */
-#define PJSIP_EINVALIDSCHEME    (PJSIP_ERRNO_START_PJSIP + 2)
+#define PJSIP_EMISSINGHDR       (PJSIP_ERRNO_START_PJSIP + 24)	/* 171024 */
+/**
+ * @hideinitializer
+ * Invalid Via header in response (sent-by, etc).
+ */
+#define PJSIP_EINVALIDVIA	(PJSIP_ERRNO_START_PJSIP + 25)	/* 171025 */
+/**
+ * @hideinitializer
+ * Multiple Via headers in response.
+ */
+#define PJSIP_EMULTIPLEVIA	(PJSIP_ERRNO_START_PJSIP + 26)	/* 171026 */
+
+/************************************************************
+ * TRANSPORT ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Unsupported transport type.
+ */
+#define PJSIP_EUNSUPTRANSPORT	(PJSIP_ERRNO_START_PJSIP + 40)	/* 171040 */
+/**
+ * @hideinitializer
+ * Buffer is being sent, operation still pending.
+ */
+#define PJSIP_EPENDINGTX	(PJSIP_ERRNO_START_PJSIP + 41)	/* 171041 */
+/**
+ * @hideinitializer
+ * Rx buffer overflow. See also PJSIP_EMSGTOOLONG.
+ */
+#define PJSIP_ERXOVERFLOW         (PJSIP_ERRNO_START_PJSIP + 42)/* 171042 */
+
+
+/************************************************************
+ * TRANSACTION ERRORS
+ ***********************************************************/
 /**
  * @hideinitializer
  * Transaction has just been destroyed.
  */
-#define PJSIP_ETSXDESTROYED     (PJSIP_ERRNO_START_PJSIP + 3)
-/**
- * @hideinitializer
- * Buffer overflow. See also PJSIP_EMSGTOOLONG.
- */
-#define PJSIP_EOVERFLOW         (PJSIP_ERRNO_START_PJSIP + 4)
-/**
- * @hideinitializer
- * Message not completely received.
- */
-#define PJSIP_EPARTIALMSG       (PJSIP_ERRNO_START_PJSIP + 5)
-/**
- * @hideinitializer
- * Message too long. See also PJSIP_EOVERFLOW.
- */
-#define PJSIP_EMSGTOOLONG	(PJSIP_ERRNO_START_PJSIP + 6)
-/**
- * @hideinitializer
- * Buffer is being sent, operation still pending.
- */
-#define PJSIP_EPENDINGTX	(PJSIP_ERRNO_START_PJSIP + 7)
-/**
- * @hideinitializer
- * Unsupported transport type.
- */
-#define PJSIP_EUNSUPTRANSPORT	(PJSIP_ERRNO_START_PJSIP + 8)
-/**
- * @hideinitializer
- * Invalid Via header in response (sent-by, etc).
- */
-#define PJSIP_EINVALIDVIA	(PJSIP_ERRNO_START_PJSIP + 9)
-/**
- * @hideinitializer
- * Multiple Via headers in response.
- */
-#define PJSIP_EMULTIPLEVIA	(PJSIP_ERRNO_START_PJSIP + 9)
-/**
- * @hideinitializer
- * SIP object is busy.
- */
-#define PJSIP_EBUSY		(PJSIP_ERRNO_START_PJSIP + 10)
-/**
- * @hideinitializer
- * SIP object with the same type already exists.
- */
-#define PJSIP_ETYPEEXISTS	(PJSIP_ERRNO_START_PJSIP + 11)
-
-
+#define PJSIP_ETSXDESTROYED     (PJSIP_ERRNO_START_PJSIP + 60)	/* 171060 */
+
+
+/************************************************************
+ * URI COMPARISON RESULTS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Scheme mismatch.
+ */
+#define PJSIP_ECMPSCHEME	(PJSIP_ERRNO_START_PJSIP + 80)	/* 171080 */
+/**
+ * @hideinitializer
+ * User part mismatch.
+ */
+#define PJSIP_ECMPUSER		(PJSIP_ERRNO_START_PJSIP + 81)	/* 171081 */
+/**
+ * @hideinitializer
+ * Password part mismatch.
+ */
+#define PJSIP_ECMPPASSWD	(PJSIP_ERRNO_START_PJSIP + 82)	/* 171082 */
+/**
+ * @hideinitializer
+ * Host part mismatch.
+ */
+#define PJSIP_ECMPHOST		(PJSIP_ERRNO_START_PJSIP + 83)	/* 171083 */
+/**
+ * @hideinitializer
+ * Port part mismatch.
+ */
+#define PJSIP_ECMPPORT		(PJSIP_ERRNO_START_PJSIP + 84)	/* 171084 */
+/**
+ * @hideinitializer
+ * Transport parameter part mismatch.
+ */
+#define PJSIP_ECMPTRANSPORTPRM	(PJSIP_ERRNO_START_PJSIP + 85)	/* 171085 */
+/**
+ * @hideinitializer
+ * TTL parameter part mismatch.
+ */
+#define PJSIP_ECMPTTLPARAM	(PJSIP_ERRNO_START_PJSIP + 86)	/* 171086 */
+/**
+ * @hideinitializer
+ * User parameter part mismatch.
+ */
+#define PJSIP_ECMPUSERPARAM	(PJSIP_ERRNO_START_PJSIP + 87)	/* 171087 */
+/**
+ * @hideinitializer
+ * Method parameter part mismatch.
+ */
+#define PJSIP_ECMPMETHODPARAM	(PJSIP_ERRNO_START_PJSIP + 88)	/* 171088 */
+/**
+ * @hideinitializer
+ * Maddr parameter part mismatch.
+ */
+#define PJSIP_ECMPMADDRPARAM	(PJSIP_ERRNO_START_PJSIP + 89)	/* 171089 */
+/**
+ * @hideinitializer
+ * Parameter part in other_param mismatch.
+ */
+#define PJSIP_ECMPOTHERPARAM	(PJSIP_ERRNO_START_PJSIP + 90)	/* 171090 */
+/**
+ * @hideinitializer
+ * Parameter part in header_param mismatch.
+ */
+#define PJSIP_ECMPHEADERPARAM	(PJSIP_ERRNO_START_PJSIP + 91)	/* 171091 */
+
+
+
+PJ_END_DECL
 
 #endif	/* __PJSIP_SIP_ERRNO_H__ */
Index: pjproject/trunk/pjsip/include/pjsip/sip_event.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_event.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/sip_event.h	(revision 64)
@@ -298,5 +298,5 @@
  * Get the event string from the event ID.
  * @param e the event ID.
- * @notes defined in sip_misc.c
+ * @notes defined in sip_util.c
  */
 PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e);
Index: pjproject/trunk/pjsip/include/pjsip/sip_misc.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_misc.h	(revision 63)
+++ 	(revision )
@@ -1,192 +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_MISC_H__
-#define __PJSIP_SIP_MISC_H__
-
-#include <pjsip/sip_msg.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_ENDPT SIP Endpoint
- * @ingroup PJSIP
- * @{
- */
-
-/**
- * Create an independent request message. This can be used to build any
- * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request
- * inside a dialog, application should use #pjsip_dlg_create_request.
- *
- * Once a transmit data is created, the reference counter is initialized to 1.
- *
- * @param endpt	    Endpoint instance.
- * @param method    SIP Method.
- * @param target    Target URI.
- * @param from	    URL to put in From header.
- * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
- * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
- * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
- * @param text	    Optional text body (put NULL to omit body).
- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, 
-						 const pjsip_method *method,
-						 const pj_str_t *target,
-						 const pj_str_t *from,
-						 const pj_str_t *to, 
-						 const pj_str_t *contact,
-						 const pj_str_t *call_id,
-						 int cseq, 
-						 const pj_str_t *text,
-						 pjsip_tx_data **p_tdata);
-
-/**
- * Create an independent request message from the specified headers. This
- * function will shallow clone the headers and put them in the request.
- *
- * Once a transmit data is created, the reference counter is initialized to 1.
- *
- * @param endpt	    Endpoint instance.
- * @param method    SIP Method.
- * @param target    Target URI.
- * @param from	    URL to put in From header.
- * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
- * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
- * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
- * @param text	    Optional text body (put NULL to omit body).
- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t)
-pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
-				     const pjsip_method *method,
-				     const pjsip_uri *target,
-				     const pjsip_from_hdr *from,
-				     const pjsip_to_hdr *to,
-				     const pjsip_contact_hdr *contact,
-				     const pjsip_cid_hdr *call_id,
-				     int cseq,
-				     const pj_str_t *text,
-				     pjsip_tx_data **p_tdata);
-
-/**
- * Send outgoing request and initiate UAC transaction for the request.
- * This is an auxiliary function to be used by application to send arbitrary
- * requests outside a dialog. To send a request within a dialog, application
- * should use #pjsip_dlg_send_msg instead.
- *
- * @param endpt	    The endpoint instance.
- * @param tdata	    The transmit data to be sent.
- * @param timeout   Optional timeout for final response to be received, or -1 
- *		    if the transaction should not have a timeout restriction.
- * @param token	    Optional token to be associated with the transaction, and 
- *		    to be passed to the callback.
- * @param cb	    Optional callback to be called when the transaction has
- *		    received a final response. The callback will be called with
- *		    the previously registered token and the event that triggers
- *		    the completion of the transaction.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt,
-					       pjsip_tx_data *tdata,
-					       int timeout,
-					       void *token,
-					       void (*cb)(void*,pjsip_event*));
-
-/**
- * Construct a minimal response message for the received request. This function
- * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and 
- * Call-ID headers from the request.
- *
- * Note: the txdata reference counter is set to ZERO!.
- *
- * @param endpt	    The endpoint.
- * @param rdata	    The request receive data.
- * @param code	    Status code to be put in the response.
- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
-						  const pjsip_rx_data *rdata,
-						  int code,
-						  pjsip_tx_data **p_tdata);
-
-/**
- * Construct a full ACK request for the received non-2xx final response.
- * This utility function is normally called by the transaction to construct
- * an ACK request to 3xx-6xx final response.
- * The generation of ACK message for 2xx final response is different than
- * this one.
- * 
- * @param endpt	    The endpoint.
- * @param tdata	    On input, this contains the original INVITE request, and on
- *		    output, it contains the ACK message.
- * @param rdata	    The final response message.
- */
-PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt,
-				      pjsip_tx_data *tdata,
-				      const pjsip_rx_data *rdata );
-
-
-/**
- * Construct CANCEL request for the previously sent request.
- *
- * @param endpt	    The endpoint.
- * @param tdata	    The transmit buffer for the request being cancelled.
- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
-						pjsip_tx_data *tdata,
-						pjsip_tx_data **p_tdata);
-
-
-/**
- * Get the address parameters (host, port, flag, TTL, etc) to send the
- * response.
- *
- * @param pool	    The pool.
- * @param tr	    The transport where the request was received.
- * @param via	    The top-most Via header of the request.
- * @param addr	    The send address concluded from the calculation.
- *
- * @return	    zero (PJ_OK) if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
-					     const pjsip_transport *tr,
-					     const pjsip_via_hdr *via,
-					     pjsip_host_port *addr);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_MISC_H__ */
-
Index: pjproject/trunk/pjsip/include/pjsip/sip_parser.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_parser.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/sip_parser.h	(revision 64)
@@ -295,17 +295,19 @@
  * parsers.
  */
-extern
-pj_cis_t	pjsip_HOST_SPEC,	    /* For scanning host part. */
-		pjsip_DIGIT_SPEC,	    /* Decimal digits */
-		pjsip_ALPHA_SPEC,	    /* Alpha (A-Z, a-z) */
-		pjsip_ALNUM_SPEC,	    /* Decimal + Alpha. */
-		pjsip_TOKEN_SPEC,	    /* Token. */
-		pjsip_HEX_SPEC,		    /* Hexadecimal digits. */
-		pjsip_PARAM_CHAR_SPEC,	    /* For scanning pname (or pvalue when it's not quoted.) */
-		pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */
-		pjsip_PASSWD_SPEC,	    /* Password. */
-		pjsip_USER_SPEC,	    /* User */
-		pjsip_NEWLINE_OR_EOF_SPEC,  /* For eating up header.*/
-		pjsip_DISPLAY_SCAN_SPEC;    /* Used when searching for display name in URL. */
+extern pj_cis_t    
+    pjsip_HOST_SPEC,		/**< For scanning host part. */
+    pjsip_DIGIT_SPEC,		/**< Decimal digits */
+    pjsip_ALPHA_SPEC,		/**< Alpha (A-Z, a-z) */
+    pjsip_ALNUM_SPEC,		/**< Decimal + Alpha. */
+    pjsip_TOKEN_SPEC,		/**< Token. */
+    pjsip_HEX_SPEC,	        /**< Hexadecimal digits. */
+    pjsip_PARAM_CHAR_SPEC,      /**< For scanning pname (or pvalue when it's 
+				     not quoted.) */
+    pjsip_HDR_CHAR_SPEC,	/**< Chars in hname/havalue in URL. */
+    pjsip_PROBE_USER_HOST_SPEC, /**< Hostname characters. */
+    pjsip_PASSWD_SPEC,		/**< Password. */
+    pjsip_USER_SPEC,		/**< User */
+    pjsip_NEWLINE_OR_EOF_SPEC,  /**< For eating up header.*/
+    pjsip_DISPLAY_SCAN_SPEC;    /**< Used when searching for display name. */
 
 /*
Index: pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 64)
@@ -130,4 +130,21 @@
 
 
+/**
+ * Create new transaction. Application would normally use 
+ * #pjsip_endpt_create_tsx rather than this function.
+ *
+ * @param pool	    Pool to use by the transaction.
+ * @param endpt	    Endpoint.
+ * @param p_tsx	    Pointer to return the transaction.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ *
+ * @see pjsip_endpt_create_tsx
+ *
+ */
+PJ_DEF(pj_status_t) pjsip_tsx_create( pj_pool_t *pool,
+				      pjsip_endpoint *endpt,
+				      pjsip_transaction **p_tsx);
+
 /** 
  * Init transaction as UAC from the specified transmit data (\c tdata).
Index: pjproject/trunk/pjsip/include/pjsip/sip_uri.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_uri.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip/sip_uri.h	(revision 64)
@@ -27,4 +27,5 @@
 #include <pjsip/sip_types.h>
 #include <pjsip/sip_config.h>
+#include <pj/list.h>
 
 PJ_BEGIN_DECL
@@ -37,4 +38,51 @@
  * @{
  */
+
+/**
+ * Generic parameter, normally used in other_param or header_param.
+ */
+typedef struct pjsip_param
+{
+    PJ_DECL_LIST_MEMBER(struct pjsip_param);	/**< Generic list member.   */
+    pj_str_t	    name;			/**< Param/header name.	    */
+    pj_str_t	    value;			/**< Param/header value.    */
+} pjsip_param;
+
+
+/**
+ * Find the specified parameter name in the list. The name will be compared
+ * in case-insensitive comparison.
+ *
+ * @param param_list	List of parameters to find.
+ * @param name		Parameter/header name to find.
+ *
+ * @return		The parameter if found, or NULL.
+ */
+PJ_DECL(pjsip_param*) pjsip_param_find( pjsip_param *param_list,
+					const pj_str_t *name );
+
+
+/**
+ * Find the specified parameter name in the list. The name will be compared
+ * in case-insensitive comparison.
+ *
+ * @param param_list	List of parameters to find.
+ * @param name		Parameter/header name to find.
+ *
+ * @return		The parameter if found, or NULL.
+ */
+PJ_DECL(const pjsip_param*) pjsip_param_cfind(const pjsip_param *param_list,
+					      const pj_str_t *name );
+
+
+/**
+ * Duplicate the parameters.
+ *
+ * @param pool		Pool to allocate memory from.
+ * @param dst_list	Destination list.
+ * @param src_list	Source list.
+ */
+PJ_DECL(void) pjsip_param_clone(pj_pool_t *pool, pjsip_param *dst_list,
+				const pjsip_param *src_list);
 
 /**
@@ -90,8 +138,9 @@
      * @param uri1 the first URI (self).
      * @param uri2 the second URI.
-     * @return zero if equal.
-     */
-    int	(*p_compare)(pjsip_uri_context_e context, 
-		     const void *uri1, const void *uri2);
+     * @return PJ_SUCCESS if equal, or otherwise the error status which
+     *		    should point to the mismatch part.
+     */
+    pj_status_t	(*p_compare)(pjsip_uri_context_e context, 
+			     const void *uri1, const void *uri2);
 
     /** 
@@ -138,5 +187,4 @@
 #define PJSIP_URI_SCHEME_IS_TEL(url)	\
     (pj_strnicmp2(pjsip_uri_get_scheme(url), "tel", 3)==0)
-
 
 
@@ -157,6 +205,6 @@
     int		    lr_param;		/**< Optional loose routing param, or zero */
     pj_str_t	    maddr_param;	/**< Optional maddr param */
-    pj_str_t	    other_param;	/**< Other parameters grouped together. */
-    pj_str_t	    header_param;	/**< Optional header parameter. */
+    pjsip_param	    other_param;	/**< Other parameters grouped together. */
+    pjsip_param	    header_param;	/**< Optional header parameter. */
 } pjsip_url;
 
@@ -208,8 +256,9 @@
  * @param uri1	    The first URI.
  * @param uri2	    The second URI.
- * @return	    Zero if equal.
- */
-PJ_INLINE(int) pjsip_uri_cmp(pjsip_uri_context_e context, 
-			     const void *uri1, const void *uri2)
+ * @return	    PJ_SUCCESS if equal, or otherwise the error status which
+ *		    should point to the mismatch part.
+ */
+PJ_INLINE(pj_status_t) pjsip_uri_cmp(pjsip_uri_context_e context, 
+				     const void *uri1, const void *uri2)
 {
     return (*((const pjsip_uri*)uri1)->vptr->p_compare)(context, uri1, uri2);
Index: pjproject/trunk/pjsip/include/pjsip/sip_util.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_util.h	(revision 64)
+++ pjproject/trunk/pjsip/include/pjsip/sip_util.h	(revision 64)
@@ -0,0 +1,192 @@
+/* $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_MISC_H__
+#define __PJSIP_SIP_MISC_H__
+
+#include <pjsip/sip_msg.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJSIP_ENDPT SIP Endpoint
+ * @ingroup PJSIP
+ * @{
+ */
+
+/**
+ * Create an independent request message. This can be used to build any
+ * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request
+ * inside a dialog, application should use #pjsip_dlg_create_request.
+ *
+ * Once a transmit data is created, the reference counter is initialized to 1.
+ *
+ * @param endpt	    Endpoint instance.
+ * @param method    SIP Method.
+ * @param target    Target URI.
+ * @param from	    URL to put in From header.
+ * @param to	    URL to put in To header.
+ * @param contact   URL to put in Contact header.
+ * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
+ * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
+ * @param text	    Optional text body (put NULL to omit body).
+ * @param p_tdata   Pointer to receive the transmit data.
+ *
+ * @return	    PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, 
+						 const pjsip_method *method,
+						 const pj_str_t *target,
+						 const pj_str_t *from,
+						 const pj_str_t *to, 
+						 const pj_str_t *contact,
+						 const pj_str_t *call_id,
+						 int cseq, 
+						 const pj_str_t *text,
+						 pjsip_tx_data **p_tdata);
+
+/**
+ * Create an independent request message from the specified headers. This
+ * function will shallow clone the headers and put them in the request.
+ *
+ * Once a transmit data is created, the reference counter is initialized to 1.
+ *
+ * @param endpt	    Endpoint instance.
+ * @param method    SIP Method.
+ * @param target    Target URI.
+ * @param from	    URL to put in From header.
+ * @param to	    URL to put in To header.
+ * @param contact   URL to put in Contact header.
+ * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
+ * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
+ * @param text	    Optional text body (put NULL to omit body).
+ * @param p_tdata   Pointer to receive the transmit data.
+ *
+ * @return	    PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
+				     const pjsip_method *method,
+				     const pjsip_uri *target,
+				     const pjsip_from_hdr *from,
+				     const pjsip_to_hdr *to,
+				     const pjsip_contact_hdr *contact,
+				     const pjsip_cid_hdr *call_id,
+				     int cseq,
+				     const pj_str_t *text,
+				     pjsip_tx_data **p_tdata);
+
+/**
+ * Send outgoing request and initiate UAC transaction for the request.
+ * This is an auxiliary function to be used by application to send arbitrary
+ * requests outside a dialog. To send a request within a dialog, application
+ * should use #pjsip_dlg_send_msg instead.
+ *
+ * @param endpt	    The endpoint instance.
+ * @param tdata	    The transmit data to be sent.
+ * @param timeout   Optional timeout for final response to be received, or -1 
+ *		    if the transaction should not have a timeout restriction.
+ * @param token	    Optional token to be associated with the transaction, and 
+ *		    to be passed to the callback.
+ * @param cb	    Optional callback to be called when the transaction has
+ *		    received a final response. The callback will be called with
+ *		    the previously registered token and the event that triggers
+ *		    the completion of the transaction.
+ *
+ * @return	    PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt,
+					       pjsip_tx_data *tdata,
+					       int timeout,
+					       void *token,
+					       void (*cb)(void*,pjsip_event*));
+
+/**
+ * Construct a minimal response message for the received request. This function
+ * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and 
+ * Call-ID headers from the request.
+ *
+ * Note: the txdata reference counter is set to ZERO!.
+ *
+ * @param endpt	    The endpoint.
+ * @param rdata	    The request receive data.
+ * @param code	    Status code to be put in the response.
+ * @param p_tdata   Pointer to receive the transmit data.
+ *
+ * @return	    PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
+						  const pjsip_rx_data *rdata,
+						  int code,
+						  pjsip_tx_data **p_tdata);
+
+/**
+ * Construct a full ACK request for the received non-2xx final response.
+ * This utility function is normally called by the transaction to construct
+ * an ACK request to 3xx-6xx final response.
+ * The generation of ACK message for 2xx final response is different than
+ * this one.
+ * 
+ * @param endpt	    The endpoint.
+ * @param tdata	    On input, this contains the original INVITE request, and on
+ *		    output, it contains the ACK message.
+ * @param rdata	    The final response message.
+ */
+PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt,
+				      pjsip_tx_data *tdata,
+				      const pjsip_rx_data *rdata );
+
+
+/**
+ * Construct CANCEL request for the previously sent request.
+ *
+ * @param endpt	    The endpoint.
+ * @param tdata	    The transmit buffer for the request being cancelled.
+ * @param p_tdata   Pointer to receive the transmit data.
+ *
+ * @return	    PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
+						pjsip_tx_data *tdata,
+						pjsip_tx_data **p_tdata);
+
+
+/**
+ * Get the address parameters (host, port, flag, TTL, etc) to send the
+ * response.
+ *
+ * @param pool	    The pool.
+ * @param tr	    The transport where the request was received.
+ * @param via	    The top-most Via header of the request.
+ * @param addr	    The send address concluded from the calculation.
+ *
+ * @return	    zero (PJ_OK) if successfull.
+ */
+PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
+					     const pjsip_transport *tr,
+					     const pjsip_via_hdr *via,
+					     pjsip_host_port *addr);
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif	/* __PJSIP_SIP_MISC_H__ */
+
Index: pjproject/trunk/pjsip/include/pjsip_core.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip_core.h	(revision 63)
+++ pjproject/trunk/pjsip/include/pjsip_core.h	(revision 64)
@@ -21,7 +21,8 @@
 
 #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_misc.h>
 #include <pjsip/sip_module.h>
 #include <pjsip/sip_msg.h>
@@ -31,5 +32,5 @@
 #include <pjsip/sip_transport.h>
 #include <pjsip/sip_uri.h>
-#include <pjsip/sip_auth.h>
+#include <pjsip/sip_util.h>
 
 #endif	/* __PJSIP_CORE_H__ */
Index: pjproject/trunk/pjsip/src/pjsip-simple/event_notify.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/event_notify.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip-simple/event_notify.c	(revision 64)
@@ -19,5 +19,5 @@
 #include <pjsip_simple/event_notify.h>
 #include <pjsip/sip_msg.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_endpoint.h>
 #include <pjsip/sip_module.h>
Index: pjproject/trunk/pjsip/src/pjsip-simple/messaging.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/messaging.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip-simple/messaging.c	(revision 64)
@@ -23,5 +23,5 @@
 #include <pjsip/sip_event.h>
 #include <pjsip/sip_module.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pj/string.h>
 #include <pj/pool.h>
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_dialog.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_dialog.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_dialog.c	(revision 64)
@@ -25,5 +25,5 @@
 #include <pjsip/sip_endpoint.h>
 #include <pjsip/sip_uri.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_module.h>
 #include <pjsip/sip_event.h>
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 64)
@@ -23,5 +23,5 @@
 #include <pjsip/sip_transaction.h>
 #include <pjsip/sip_event.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_auth_msg.h>
 #include <pj/pool.h>
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_ua.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_ua.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_ua.c	(revision 64)
@@ -22,5 +22,5 @@
 #include <pjsip/sip_module.h>
 #include <pjsip/sip_event.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_endpoint.h>
 #include <pjsip/sip_transaction.h>
Index: pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 64)
@@ -23,5 +23,5 @@
 #include <pjsip/sip_resolve.h>
 #include <pjsip/sip_module.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_errno.h>
 #include <pj/except.h>
@@ -107,11 +107,4 @@
 
 /*
- * Create transaction.
- * Defined in sip_transaction.c
- */
-pj_status_t pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt,
-                              pjsip_transaction **tsx );
-
-/*
  * This is the global handler for memory allocation failure, for pools that
  * are created by the endpoint (by default, all pools ARE allocated by 
@@ -295,5 +288,5 @@
  * Get "Allow" header.
  */
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
+PJ_DEF(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
 {
     return endpt->allow_hdr;
@@ -672,5 +665,5 @@
  * Find transaction by the key.
  */
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
+PJ_DEF(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
 					          const pj_str_t *key )
 {
@@ -981,5 +974,5 @@
  * Find/create transport.
  */
-PJ_DECL(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt,
+PJ_DEF(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt,
 						  pjsip_transport_type_e type,
 						  const pj_sockaddr_in *remote,
@@ -992,4 +985,48 @@
 
 
+/*
+ * Report error.
+ */
+PJ_DEF(void) pjsip_endpt_log_error(  pjsip_endpoint *endpt,
+				     const char *sender,
+                                     pj_status_t error_code,
+                                     const char *format,
+                                     ... )
+{
+    char newformat[256];
+    int len;
+    va_list marker;
+
+    va_start(marker, format);
+
+    PJ_UNUSED_ARG(endpt);
+
+    len = pj_native_strlen(format);
+    if (len < sizeof(newformat)-30) {
+	pj_str_t errstr;
+
+	pj_native_strcpy(newformat, format);
+	pj_snprintf(newformat+len, sizeof(newformat)-len-1,
+		    ": [err %d] ", error_code);
+	len += pj_native_strlen(newformat+len);
+
+	errstr = pjsip_strerror(error_code, newformat+len, 
+				sizeof(newformat)-len-1);
+
+	len += errstr.slen;
+	newformat[len] = '\0';
+
+	pj_log(sender, 1, newformat, marker);
+    } else {
+	pj_log(sender, 1, format, marker);
+    }
+
+    va_end(marker);
+}
+
+
+/*
+ * Dump endpoint.
+ */
 PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
 {
Index: pjproject/trunk/pjsip/src/pjsip/sip_errno.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_errno.c	(revision 64)
+++ pjproject/trunk/pjsip/src/pjsip/sip_errno.c	(revision 64)
@@ -0,0 +1,125 @@
+/* $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_errno.h>
+#include <pjsip/sip_msg.h>
+#include <pj/string.h>
+#include <pj/errno.h>
+
+/* PJSIP's own error codes/messages 
+ * MUST KEEP THIS ARRAY SORTED!!
+ */
+static const struct 
+{
+    int code;
+    const char *msg;
+} err_str[] = 
+{
+    /* Generic SIP errors */
+    { PJSIP_EBUSY,		"Object is busy" },
+    { PJSIP_ETYPEEXISTS ,	"Object with the same type exists" },
+
+    /* Messaging errors */
+    { PJSIP_EINVALIDMSG,	"Invalid message/syntax error" },
+    { PJSIP_EINVALIDSCHEME,	"Invalid URI scheme" },
+    { PJSIP_EMSGTOOLONG,	"Message too long" },
+    { PJSIP_EPARTIALMSG,	"Partial message" },
+    { PJSIP_EMISSINGHDR,	"Missing required header(s)" },
+    { PJSIP_EINVALIDVIA,	"Invalid Via header" },
+    { PJSIP_EMULTIPLEVIA,	"Multiple Via headers in response" },
+
+    /* Transport errors */
+    { PJSIP_EUNSUPTRANSPORT,	"Unsupported transport"},
+    { PJSIP_EPENDINGTX,		"Transmit buffer already pending"},
+    { PJSIP_ERXOVERFLOW,	"Rx buffer overflow"},
+
+    /* Transaction errors */
+    { PJSIP_ETSXDESTROYED,	"Transaction has been destroyed"},
+};
+
+
+/*
+ * pjsip_strerror()
+ */
+PJ_DEF(pj_str_t) pjsip_strerror( pj_status_t statcode, 
+				 char *buf, pj_size_t bufsize )
+{
+    pj_str_t errstr;
+
+    if (statcode >= PJSIP_ERRNO_START && statcode < PJSIP_ERRNO_START+800) 
+    {
+	/* Status code. */
+	const pj_str_t *status_text = 
+	    pjsip_get_status_text(PJSIP_ERRNO_TO_SIP_STATUS(statcode));
+
+	errstr.ptr = buf;
+	pj_strncpy_with_null(&errstr, status_text, bufsize);
+	return errstr;
+    }
+    else if (statcode >= PJSIP_ERRNO_START_PJSIP && 
+	     statcode < PJSIP_ERRNO_START_PJSIP + 1000)
+    {
+	/* Find the error in the table.
+	 * Use binary search!
+	 */
+	int first = 0;
+	int n = PJ_ARRAY_SIZE(err_str);
+
+	while (n > 0) {
+	    int half = n/2;
+	    int mid = first + half;
+
+	    if (err_str[mid].code < statcode) {
+		first = mid+1;
+		n -= (half+1);
+	    } else if (err_str[mid].code > statcode) {
+		n = half;
+	    } else {
+		first = mid;
+		break;
+	    }
+	}
+
+
+	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
+	    pj_str_t msg;
+	    
+	    msg.ptr = (char*)err_str[first].msg;
+	    msg.slen = pj_native_strlen(err_str[first].msg);
+
+	    errstr.ptr = buf;
+	    pj_strncpy_with_null(&errstr, &msg, bufsize);
+	    return errstr;
+
+	} else {
+	    /* Error not found. */
+	    errstr.ptr = buf;
+	    errstr.slen = pj_snprintf(buf, bufsize, 
+				      "Unknown error %d",
+				      statcode);
+
+	    return errstr;
+	}
+    }
+    else {
+	/* Not our code. Give it to PJLIB. */
+	return pj_strerror(statcode, buf, bufsize);
+    }
+
+}
+
Index: pjproject/trunk/pjsip/src/pjsip/sip_misc.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_misc.c	(revision 63)
+++ 	(revision )
@@ -1,724 +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/sip_misc.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_module.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/pool.h>
-#include <pj/except.h>
-#include <pj/rand.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-#define THIS_FILE    "endpoint"
-
-static const char *event_str[] = 
-{
-    "UNIDENTIFIED",
-    "TIMER",
-    "TX_MSG",
-    "RX_MSG",
-    "TRANSPORT_ERROR",
-    "TSX_STATE",
-    "RX_2XX_RESPONSE",
-    "RX_ACK",
-    "DISCARD_MSG",
-    "USER",
-    "BEFORE_TX",
-};
-
-static pj_str_t str_TEXT = { "text", 4},
-		str_PLAIN = { "plain", 5 };
-static int aux_mod_id;
-
-struct aux_tsx_data
-{
-    void *token;
-    void (*cb)(void*,pjsip_event*);
-};
-
-static pj_status_t aux_tsx_init( pjsip_endpoint *endpt,
-				 struct pjsip_module *mod, pj_uint32_t id )
-{
-    PJ_UNUSED_ARG(endpt);
-    PJ_UNUSED_ARG(mod);
-
-    aux_mod_id = id;
-    return 0;
-}
-
-static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_transaction *tsx;
-    struct aux_tsx_data *tsx_data;
-
-    PJ_UNUSED_ARG(mod);
-
-    if (event->type != PJSIP_EVENT_TSX_STATE)
-	return;
-
-    pj_assert(event->body.tsx_state.tsx != NULL);
-    tsx = event->body.tsx_state.tsx;
-    if (tsx == NULL)
-	return;
-    if (tsx->module_data[aux_mod_id] == NULL)
-	return;
-    if (tsx->status_code < 200)
-	return;
-
-    /* Call the callback, if any, and prevent the callback to be called again
-     * by clearing the transaction's module_data.
-     */
-    tsx_data = tsx->module_data[aux_mod_id];
-    tsx->module_data[aux_mod_id] = NULL;
-
-    if (tsx_data->cb) {
-	(*tsx_data->cb)(tsx_data->token, event);
-    }
-}
-
-pjsip_module aux_tsx_module = 
-{
-    { "Aux-Tsx", 7},	    /* Name.		*/
-    0,			    /* Flag		*/
-    128,		    /* Priority		*/
-    NULL,		    /* Arbitrary data.	*/
-    0,			    /* Number of methods supported (none). */
-    { 0 },		    /* Array of methods (none) */
-    &aux_tsx_init,	    /* init_module()	*/
-    NULL,		    /* start_module()	*/
-    NULL,		    /* deinit_module()	*/
-    &aux_tsx_handler,	    /* tsx_handler()	*/
-};
-
-PJ_DEF(pj_status_t) pjsip_endpt_send_request(  pjsip_endpoint *endpt,
-					       pjsip_tx_data *tdata,
-					       int timeout,
-					       void *token,
-					       void (*cb)(void*,pjsip_event*))
-{
-    pjsip_transaction *tsx;
-    struct aux_tsx_data *tsx_data;
-    pj_status_t status;
-
-    status = pjsip_endpt_create_tsx(endpt, &tsx);
-    if (!tsx) {
-	pjsip_tx_data_dec_ref(tdata);
-	return -1;
-    }
-
-    tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data));
-    tsx_data->token = token;
-    tsx_data->cb = cb;
-    tsx->module_data[aux_mod_id] = tsx_data;
-
-    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {
-	pjsip_endpt_destroy_tsx(endpt, tsx);
-	pjsip_tx_data_dec_ref(tdata);
-	return -1;
-    }
-
-    pjsip_endpt_register_tsx(endpt, tsx);
-    pjsip_tx_data_invalidate_msg(tdata);
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-    pjsip_tx_data_dec_ref(tdata);
-    return 0;
-}
-
-/*
- * Initialize transmit data (msg) with the headers and optional body.
- * This will just put the headers in the message as it is. Be carefull
- * when calling this function because once a header is put in a message, 
- * it CAN NOT be put in other message until the first message is deleted, 
- * because the way the header is put in the list.
- * That's why the session will shallow_clone it's headers before calling
- * this function.
- */
-static void init_request_throw( pjsip_endpoint *endpt,
-                                pjsip_tx_data *tdata, 
-				pjsip_method *method,
-				pjsip_uri *param_target,
-				pjsip_from_hdr *param_from,
-				pjsip_to_hdr *param_to, 
-				pjsip_contact_hdr *param_contact,
-				pjsip_cid_hdr *param_call_id,
-				pjsip_cseq_hdr *param_cseq, 
-				const pj_str_t *param_text)
-{
-    pjsip_msg *msg;
-    pjsip_msg_body *body;
-    const pjsip_hdr *endpt_hdr;
-
-    /* Create the message. */
-    msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
-
-    /* Init request URI. */
-    pj_memcpy(&msg->line.req.method, method, sizeof(*method));
-    msg->line.req.uri = param_target;
-
-    /* Add additional request headers from endpoint. */
-    endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next;
-    while (endpt_hdr != pjsip_endpt_get_request_headers(endpt)) {
-	pjsip_hdr *hdr = pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr);
-	pjsip_msg_add_hdr( tdata->msg, hdr );
-	endpt_hdr = endpt_hdr->next;
-    }
-
-    /* Add From header. */
-    if (param_from->tag.slen == 0)
-	pj_create_unique_string(tdata->pool, &param_from->tag);
-    pjsip_msg_add_hdr(msg, (void*)param_from);
-
-    /* Add To header. */
-    pjsip_msg_add_hdr(msg, (void*)param_to);
-
-    /* Add Contact header. */
-    if (param_contact) {
-	pjsip_msg_add_hdr(msg, (void*)param_contact);
-    }
-
-    /* Add Call-ID header. */
-    pjsip_msg_add_hdr(msg, (void*)param_call_id);
-
-    /* Add CSeq header. */
-    pjsip_msg_add_hdr(msg, (void*)param_cseq);
-
-    /* Create message body. */
-    if (param_text) {
-	body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body));
-	body->content_type.type = str_TEXT;
-	body->content_type.subtype = str_PLAIN;
-	body->data = pj_pool_alloc(tdata->pool, param_text->slen );
-	pj_memcpy(body->data, param_text->ptr, param_text->slen);
-	body->len = param_text->slen;
-	body->print_body = &pjsip_print_text_body;
-	msg->body = body;
-    }
-}
-
-/*
- * Create arbitrary request.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_request(  pjsip_endpoint *endpt, 
-						 const pjsip_method *method,
-						 const pj_str_t *param_target,
-						 const pj_str_t *param_from,
-						 const pj_str_t *param_to, 
-						 const pj_str_t *param_contact,
-						 const pj_str_t *param_call_id,
-						 int param_cseq, 
-						 const pj_str_t *param_text,
-						 pjsip_tx_data **p_tdata)
-{
-    pjsip_uri *target;
-    pjsip_tx_data *tdata;
-    pjsip_from_hdr *from;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_cseq_hdr *cseq = NULL;    /* = NULL, warning in VC6 */
-    pjsip_cid_hdr *call_id;
-    pj_str_t tmp;
-    pj_status_t status;
-    PJ_USE_EXCEPTION;
-
-    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()"));
-
-    status = pjsip_endpt_create_tdata(endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Init reference counter to 1. */
-    pjsip_tx_data_add_ref(tdata);
-
-    PJ_TRY {
-	/* Request target. */
-	pj_strdup_with_null(tdata->pool, &tmp, param_target);
-	target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0);
-	if (target == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid target %s", 
-		      tmp.ptr));
-	    goto on_error;
-	}
-
-	/* From */
-	from = pjsip_from_hdr_create(tdata->pool);
-	pj_strdup_with_null(tdata->pool, &tmp, param_from);
-	from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
-				     PJSIP_PARSE_URI_AS_NAMEADDR);
-	if (from->uri == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'",
-				tmp.ptr));
-	    goto on_error;
-	}
-	pj_create_unique_string(tdata->pool, &from->tag);
-
-	/* To */
-	to = pjsip_to_hdr_create(tdata->pool);
-	pj_strdup_with_null(tdata->pool, &tmp, param_to);
-	to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
-				   PJSIP_PARSE_URI_AS_NAMEADDR);
-	if (to->uri == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'",
-				tmp.ptr));
-	    goto on_error;
-	}
-
-	/* Contact. */
-	if (param_contact) {
-	    contact = pjsip_contact_hdr_create(tdata->pool);
-	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);
-	    contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen,
-					    PJSIP_PARSE_URI_AS_NAMEADDR);
-	    if (contact->uri == NULL) {
-		PJ_LOG(4,(THIS_FILE, 
-			  "Error creating request: invalid 'Contact' URI '%s'",
-			  tmp.ptr));
-		goto on_error;
-	    }
-	} else {
-	    contact = NULL;
-	}
-
-	/* Call-ID */
-	call_id = pjsip_cid_hdr_create(tdata->pool);
-	if (param_call_id != NULL && param_call_id->slen)
-	    pj_strdup(tdata->pool, &call_id->id, param_call_id);
-	else
-	    pj_create_unique_string(tdata->pool, &call_id->id);
-
-	/* CSeq */
-	cseq = pjsip_cseq_hdr_create(tdata->pool);
-	if (param_cseq >= 0)
-	    cseq->cseq = param_cseq;
-	else
-	    cseq->cseq = pj_rand() & 0xFFFF;
-
-	/* Method */
-	pjsip_method_copy(tdata->pool, &cseq->method, method);
-
-	/* Create the request. */
-	init_request_throw( endpt, tdata, &cseq->method, target, from, to, 
-                            contact, call_id, cseq, param_text);
-    }
-    PJ_DEFAULT {
-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-    PJ_END
-
-    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
-		        tdata->obj_name, 
-			cseq->cseq, 
-			cseq->method.name.slen,
-			cseq->method.name.ptr));
-
-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-
-on_error:
-    pjsip_tx_data_dec_ref(tdata);
-    return status;
-}
-
-PJ_DEF(pj_status_t)
-pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
-				     const pjsip_method *method,
-				     const pjsip_uri *param_target,
-				     const pjsip_from_hdr *param_from,
-				     const pjsip_to_hdr *param_to,
-				     const pjsip_contact_hdr *param_contact,
-				     const pjsip_cid_hdr *param_call_id,
-				     int param_cseq,
-				     const pj_str_t *param_text,
-				     pjsip_tx_data **p_tdata)
-{
-    pjsip_uri *target;
-    pjsip_tx_data *tdata;
-    pjsip_from_hdr *from;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_cid_hdr *call_id;
-    pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */
-    pj_status_t status;
-    PJ_USE_EXCEPTION;
-
-    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()"));
-
-    status = pjsip_endpt_create_tdata(endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    pjsip_tx_data_add_ref(tdata);
-
-    PJ_TRY {
-	target = pjsip_uri_clone(tdata->pool, param_target);
-	from = pjsip_hdr_shallow_clone(tdata->pool, param_from);
-	pjsip_fromto_set_from(from);
-	to = pjsip_hdr_shallow_clone(tdata->pool, param_to);
-	pjsip_fromto_set_to(to);
-	if (param_contact)
-	    contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact);
-	else
-	    contact = NULL;
-	call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id);
-	cseq = pjsip_cseq_hdr_create(tdata->pool);
-	if (param_cseq >= 0)
-	    cseq->cseq = param_cseq;
-	else
-	    cseq->cseq = pj_rand() % 0xFFFF;
-	pjsip_method_copy(tdata->pool, &cseq->method, method);
-
-	init_request_throw(endpt, tdata, &cseq->method, target, from, to, 
-                           contact, call_id, cseq, param_text);
-    }
-    PJ_DEFAULT {
-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-    PJ_END;
-
-    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
-			tdata->obj_name, 
-			cseq->cseq, 
-			cseq->method.name.slen,
-			cseq->method.name.ptr));
-
-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-
-on_error:
-    pjsip_tx_data_dec_ref(tdata);
-    return status;
-}
-
-/*
- * Construct a minimal response message for the received request.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
-						 const pjsip_rx_data *rdata,
-						 int code,
-						 pjsip_tx_data **p_tdata)
-{
-    pjsip_tx_data *tdata;
-    pjsip_msg *msg, *req_msg;
-    pjsip_hdr *hdr;
-    pjsip_via_hdr *via;
-    pjsip_rr_hdr *rr;
-    pj_status_t status;
-
-    /* rdata must be a request message. */
-    req_msg = rdata->msg_info.msg;
-    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", 
-		         rdata, code));
-
-    /* Create a new transmit buffer. */
-    status = pjsip_endpt_create_tdata( endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Create new response message. */
-    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);
-
-    /* Set status code and reason text. */
-    msg->line.status.code = code;
-    msg->line.status.reason = *pjsip_get_status_text(code);
-
-    /* Set TX data attributes. */
-    tdata->rx_timestamp = rdata->pkt_info.timestamp;
-
-    /* Copy all the via headers, in order. */
-    via = rdata->msg_info.via;
-    while (via) {
-	pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via));
-	via = via->next;
-	if (via != (void*)&req_msg->hdr)
-	    via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);
-	else
-	    break;
-    }
-
-    /* Copy all Record-Route headers, in order. */
-    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);
-    while (rr) {
-	pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr));
-	rr = rr->next;
-	if (rr != (void*)&req_msg->hdr)
-	    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr);
-	else
-	    break;
-    }
-
-    /* Copy Call-ID header. */
-    hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr));
-
-    /* Copy From header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from);
-    pjsip_msg_add_hdr( msg, hdr);
-
-    /* Copy To header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to);
-    pjsip_msg_add_hdr( msg, hdr);
-
-    /* Copy CSeq header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq);
-    pjsip_msg_add_hdr( msg, hdr);
-
-    /* All done. */
-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of
- * RFC3261). Note that the generation of ACK for 2xx response is different,
- * and one must not use this function to generate such ACK.
- */
-PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,
-				    pjsip_tx_data *tdata,
-				    const pjsip_rx_data *rdata )
-{
-    pjsip_msg *ack_msg, *invite_msg;
-    pjsip_to_hdr *to;
-    pjsip_from_hdr *from;
-    pjsip_cseq_hdr *cseq;
-    pjsip_hdr *hdr;
-
-    /* Make compiler happy. */
-    PJ_UNUSED_ARG(endpt);
-
-    /* rdata must be a final response. */
-    pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG &&
-	      rdata->msg_info.msg->line.status.code >= 300);
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata));
-
-    /* Create new request message. */
-    ack_msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
-    pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD );
-
-    /* The original INVITE message. */
-    invite_msg = tdata->msg;
-
-    /* Copy Request-Uri from the original INVITE. */
-    ack_msg->line.req.uri = invite_msg->line.req.uri;
-    
-    /* Copy Call-ID from the original INVITE */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr( ack_msg, hdr );
-
-    /* Copy From header from the original INVITE. */
-    from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, 
-						      PJSIP_H_FROM, NULL);
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from );
-
-    /* Copy To header from the original INVITE. */
-    to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg, 
-						   PJSIP_H_TO, NULL);
-    pj_strdup(tdata->pool, &to->tag, &rdata->msg_info.to->tag);
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to );
-
-    /* Must contain single Via, just as the original INVITE. */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL);
-    pjsip_msg_insert_first_hdr( ack_msg, hdr );
-
-    /* Must have the same CSeq value as the original INVITE, but method 
-     * changed to ACK 
-     */
-    cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, 
-							PJSIP_H_CSEQ, NULL);
-    pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD );
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq );
-
-    /* If the original INVITE has Route headers, those header fields MUST 
-     * appear in the ACK.
-     */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
-    while (hdr != NULL) {
-	pjsip_msg_add_hdr( ack_msg, hdr );
-	hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
-    }
-
-    /* Set the message in the "tdata" to point to the ACK message. */
-    tdata->msg = ack_msg;
-
-    /* Reset transmit packet buffer, to force 're-printing' of message. */
-    tdata->buf.cur = tdata->buf.start;
-
-    /* We're done.
-     * "tdata" parameter now contains the ACK message.
-     */
-}
-
-
-/*
- * Construct CANCEL request for the previously sent request, according to
- * chapter 9.1 of RFC3261.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
-					       pjsip_tx_data *req_tdata,
-					       pjsip_tx_data **p_tdata)
-{
-    pjsip_msg *req_msg;	/* the original request. */
-    pjsip_tx_data *cancel_tdata;
-    pjsip_msg *cancel_msg;
-    pjsip_hdr *hdr;
-    pjsip_cseq_hdr *req_cseq, *cseq;
-    pjsip_uri *req_uri;
-    pj_status_t status;
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata));
-
-    /* Get the original request. */
-    req_msg = req_tdata->msg;
-
-    /* The transmit buffer must INVITE request. */
-    PJ_ASSERT_RETURN(req_msg->type == PJSIP_REQUEST_MSG &&
-		     req_msg->line.req.method.id == PJSIP_INVITE_METHOD,
-		     PJ_EINVAL);
-
-    /* Create new transmit buffer. */
-    status = pjsip_endpt_create_tdata( endpt, &cancel_tdata);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-
-    /* Create CANCEL request message. */
-    cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG);
-    cancel_tdata->msg = cancel_msg;
-
-    /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are
-     * copied from the original request.
-     */
-    /* Set request line. */
-    pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD);
-    req_uri = req_msg->line.req.uri;
-    cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri);
-
-    /* Copy Call-ID */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Copy From header. */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Copy To header. */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Create new CSeq with equal number, but method set to CANCEL. */
-    req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL);
-    cseq = pjsip_cseq_hdr_create(cancel_tdata->pool);
-    cseq->cseq = req_cseq->cseq;
-    pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD);
-    pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq);
-
-    /* Must only have single Via which matches the top-most Via in the 
-     * request being cancelled. 
-     */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL);
-    pjsip_msg_insert_first_hdr(cancel_msg, 
-			       pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* If the original request has Route header, the CANCEL request must also
-     * has exactly the same.
-     * Copy "Route" header from the request.
-     */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL);
-    while (hdr != NULL) {
-	pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-	hdr = hdr->next;
-	if (hdr != &cancel_msg->hdr)
-	    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr);
-	else
-	    break;
-    }
-
-    /* Done.
-     * Return the transmit buffer containing the CANCEL request.
-     */
-    *p_tdata = cancel_tdata;
-    return PJ_SUCCESS;
-}
-
-/* Get the address parameters (host, port, flag, TTL, etc) to send the
- * response.
- */
-PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
-					    const pjsip_transport *req_transport,
-					    const pjsip_via_hdr *via,
-					    pjsip_host_port *send_addr)
-{
-    /* Determine the destination address (section 18.2.2):
-     * - for TCP, SCTP, or TLS, send the response using the transport where
-     *   the request was received.
-     * - if maddr parameter is present, send to this address using the port
-     *   in sent-by or 5060. If multicast is used, the TTL in the Via must
-     *   be used, or 1 if ttl parameter is not present.
-     * - otherwise if received parameter is present, set to this address.
-     * - otherwise send to the address in sent-by.
-     */
-    send_addr->flag = req_transport->flag;
-    send_addr->type = req_transport->type;
-
-    if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) {
-	const pj_sockaddr_in *remote_addr;
-	remote_addr = &req_transport->rem_addr;
-	pj_strdup2(pool, &send_addr->host, 
-		   pj_inet_ntoa(remote_addr->sin_addr));
-	send_addr->port = pj_sockaddr_in_get_port(remote_addr);
-
-    } else {
-	/* Set the host part */
-	if (via->maddr_param.slen) {
-	    pj_strdup(pool, &send_addr->host, &via->maddr_param);
-	} else if (via->recvd_param.slen) {
-	    pj_strdup(pool, &send_addr->host, &via->recvd_param);
-	} else {
-	    pj_strdup(pool, &send_addr->host, &via->sent_by.host);
-	}
-
-	/* Set the port */
-	send_addr->port = via->sent_by.port;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Get the event string from the event ID.
- */
-PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)
-{
-    return event_str[e];
-}
-
Index: pjproject/trunk/pjsip/src/pjsip/sip_parser.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_parser.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip/sip_parser.c	(revision 64)
@@ -24,4 +24,5 @@
 #include <pjsip/sip_transport.h>        /* rdata structure */
 #include <pjlib-util/scanner.h>
+#include <pjlib-util/string.h>
 #include <pj/except.h>
 #include <pj/log.h>
@@ -33,14 +34,18 @@
 #include <pj/assert.h>
 
-#define RESERVED    ";/?:@&=+$,"
-#define MARK	    "-_.!~*'()"
-#define ESCAPED	    "%"
-#define USER	    "&=+$,;?/"
-#define PASS	    "&=+$,"
-#define TOKEN	    "-.!%*_=`'~+"   /* '+' is because of application/pidf+xml
-                                     * in Content-Type! */
-#define HOST	    "_-."
-#define HEX_DIGIT   "abcdefABCDEF"
-#define PARAM_CHAR  "[]/:&+$" MARK "%"
+#define ALNUM
+#define RESERVED	    ";/?:@&=+$,"
+#define MARK		    "-_.!~*'()"
+#define UNRESERVED	    ALNUM MARK
+#define ESCAPED		    "%"
+#define USER_UNRESERVED	    "&=+$,;?/"
+#define PASS		    "&=+$,"
+#define TOKEN		    "-.!%*_=`'~+"   /* '+' is because of app/pidf+xml
+					     * in Content-Type! */
+#define HOST		    "_-."
+#define HEX_DIGIT	    "abcdefABCDEF"
+#define PARAM_CHAR	    "[]/:&+$" UNRESERVED ESCAPED
+#define HNV_UNRESERVED	    "[]/?:+$"
+#define HDR_CHAR	    HNV_UNRESERVED UNRESERVED ESCAPED
 
 #define PJSIP_VERSION		"SIP/2.0"
@@ -93,4 +98,5 @@
 	    pjsip_PARAM_CHAR_SPEC,      /* For scanning pname (or pvalue when
                                          * it's not quoted.) */
+	    pjsip_HDR_CHAR_SPEC,	/* Chars in hname or hvalue */
 	    pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */
 	    pjsip_PASSWD_SPEC,	        /* Password. */
@@ -110,4 +116,7 @@
 				     pj_str_t *pname, 
 				     pj_str_t *pvalue);
+static void	    int_parse_hparam( pj_scanner *scanner,
+				      pj_str_t *hname,
+				      pj_str_t *hvalue );
 static void         int_parse_req_line( pj_scanner *scanner, 
 					pj_pool_t *pool,
@@ -272,7 +281,11 @@
     pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR);
 
+    status = pj_cis_dup(&pjsip_HDR_CHAR_SPEC, &pjsip_ALNUM_SPEC);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+    pj_cis_add_str(&pjsip_HDR_CHAR_SPEC, HDR_CHAR);
+
     status = pj_cis_dup(&pjsip_USER_SPEC, &pjsip_ALNUM_SPEC);
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_USER_SPEC, MARK ESCAPED USER );
+    pj_cis_add_str( &pjsip_USER_SPEC, ESCAPED USER_UNRESERVED );
 
     status = pj_cis_dup(&pjsip_PASSWD_SPEC, &pjsip_ALNUM_SPEC);
@@ -859,4 +872,5 @@
     /* pname */
     pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pname);
+    pj_str_unescape(pname);
 
     /* pvalue, if any */
@@ -872,4 +886,5 @@
 	} else {
 	    pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pvalue);
+	    pj_str_unescape(pvalue);
 	}
     } else {
@@ -890,4 +905,26 @@
 }
 
+/* Parse header parameter. */
+static void int_parse_hparam( pj_scanner *scanner,
+			      pj_str_t *hname, pj_str_t *hvalue )
+{
+    /* Get '?' or '&' character. */
+    pj_scan_get_char(scanner);
+
+    /* hname */
+    pj_scan_get(scanner, &pjsip_HDR_CHAR_SPEC, hname);
+    pj_str_unescape(hname);
+
+    /* pvalue, if any */
+    if (*scanner->curptr == '=') {
+	pj_scan_get_char(scanner);
+	pj_scan_get(scanner, &pjsip_HDR_CHAR_SPEC, hvalue);
+	pj_str_unescape(hvalue);
+    } else {
+	hvalue->ptr = NULL;
+	hvalue->slen = 0;
+    }
+}
+
 /* Parse host:port in URI. */
 static void int_parse_uri_host_port( pj_scanner *scanner, 
@@ -895,8 +932,10 @@
 {
     pj_scan_get( scanner, &pjsip_HOST_SPEC, host);
+    /* RFC3261 section 19.1.2: host don't need to be unescaped */
     if (*scanner->curptr == ':') {
 	pj_str_t port;
 	pj_scan_get_char(scanner);
 	pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port);
+	pj_str_unescape(&port);
 	*p_port = pj_strtoul(&port);
     } else {
@@ -927,7 +966,10 @@
 {
     pj_scan_get( scanner, &pjsip_USER_SPEC, user);
+    pj_str_unescape(user);
+
     if ( *scanner->curptr == ':') {
 	pj_scan_get_char( scanner );
 	pj_scan_get( scanner, &pjsip_PASSWD_SPEC, pass);
+	pj_str_unescape(pass);
     } else {
 	pass->ptr = NULL;
@@ -945,4 +987,7 @@
     pjsip_uri *uri;
     int is_name_addr = 0;
+
+    /* Exhaust any whitespaces. */
+    pj_scan_skip_whitespace(scanner);
 
     if (*scanner->curptr=='"' || *scanner->curptr=='<') {
@@ -1035,4 +1080,5 @@
     int colon;
     int skip_ws = scanner->skip_ws;
+    int hsep = '?';
     scanner->skip_ws = 0;
 
@@ -1090,12 +1136,18 @@
 
 	} else {
-	    concat_param(&url->other_param, pool, &pname, &pvalue);
+	    pjsip_param *p = pj_pool_alloc(pool, sizeof(pjsip_param));
+	    p->name = pname;
+	    p->value = pvalue;
+	    pj_list_insert_before(&url->other_param, p);
 	}
     }
 
     /* Get header params. */
-    if (parse_params && *scanner->curptr == '?') {
-	pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, 
-                          &url->header_param);
+    while (parse_params && *scanner->curptr == hsep) {
+	pjsip_param *param;
+	param = pj_pool_alloc(pool, sizeof(pjsip_param));
+	int_parse_hparam(scanner, &param->name, &param->value);
+	pj_list_insert_before(&url->header_param, param);
+	hsep = '&';
     }
 
Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 64)
@@ -20,5 +20,5 @@
 #include <pjsip/sip_transport.h>
 #include <pjsip/sip_config.h>
-#include <pjsip/sip_misc.h>
+#include <pjsip/sip_util.h>
 #include <pjsip/sip_event.h>
 #include <pjsip/sip_endpoint.h>
@@ -346,7 +346,7 @@
  * Create new transaction.
  */
-pj_status_t pjsip_tsx_create( pj_pool_t *pool,
-			      pjsip_endpoint *endpt,
-                              pjsip_transaction **p_tsx)
+PJ_DEF(pj_status_t) pjsip_tsx_create( pj_pool_t *pool,
+				      pjsip_endpoint *endpt,
+				      pjsip_transaction **p_tsx)
 {
     pjsip_transaction *tsx;
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 64)
@@ -648,5 +648,5 @@
 	    if (msg_status != PJ_SUCCESS) {
 		if (remaining_len == PJSIP_MAX_PKT_LEN) {
-		    mgr->msg_cb(mgr->endpt, PJSIP_EOVERFLOW, rdata);
+		    mgr->msg_cb(mgr->endpt, PJSIP_ERXOVERFLOW, rdata);
 		    /* Exhaust all data. */
 		    return rdata->pkt_info.len;
Index: pjproject/trunk/pjsip/src/pjsip/sip_uri.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_uri.c	(revision 63)
+++ pjproject/trunk/pjsip/src/pjsip/sip_uri.c	(revision 64)
@@ -19,9 +19,57 @@
 #include <pjsip/sip_uri.h>
 #include <pjsip/sip_msg.h>
+#include <pjsip/sip_parser.h>
 #include <pjsip/print_util.h>
+#include <pjsip/sip_errno.h>
+#include <pjlib-util/string.h>
 #include <pj/string.h>
 #include <pj/pool.h>
 #include <pj/assert.h>
 
+/*
+ * Generic parameter manipulation.
+ */
+PJ_DEF(pjsip_param*) pjsip_param_find(  pjsip_param *param_list,
+					const pj_str_t *name )
+{
+    pjsip_param *p = param_list->next;
+    while (p != param_list) {
+	if (pj_stricmp(&p->name, name)==0)
+	    return p;
+	p = p->next;
+    }
+    return NULL;
+}
+
+PJ_DEF(const pjsip_param*) pjsip_param_cfind( const pjsip_param *param_list,
+					      const pj_str_t *name )
+{
+    const pjsip_param *p = param_list->next;
+    while (p != param_list) {
+	if (pj_stricmp(&p->name, name)==0)
+	    return p;
+	p = p->next;
+    }
+    return NULL;
+}
+
+PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list,
+				const pjsip_param *src_list)
+{
+    const pjsip_param *p = src_list->next;
+
+    pj_list_init(dst_list);
+    while (p != src_list) {
+	pjsip_param *new_param = pj_pool_alloc(pool, sizeof(pjsip_param));
+	pj_strdup(pool, &new_param->name, &p->name);
+	pj_strdup(pool, &new_param->value, &p->value);
+	pj_list_insert_before(dst_list, new_param);
+	p = p->next;
+    }
+}
+
+/*
+ * URI stuffs
+ */
 #define IS_SIPS(url)	((url)->vptr==&sips_url_vptr)
 
@@ -110,4 +158,6 @@
     url->ttl_param = -1;
     url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
+    pj_list_init(&url->other_param);
+    pj_list_init(&url->header_param);
 }
 
@@ -124,35 +174,23 @@
 {
     int printed;
-    pj_size_t size_required;
     char *startbuf = buf;
+    char *endbuf = buf+size;
     const pj_str_t *scheme;
+    pjsip_param *param;
+    char hparam_char = '?';
+
     *buf = '\0';
-
-    /* Check the buffer length. */
-    size_required = 6 + url->host.slen + 10 +
-		    url->user.slen + url->passwd.slen + 2 +
-		    url->user_param.slen + 6 +
-		    url->method_param.slen + 8 +
-		    url->transport_param.slen + 11 +
-		    9 + 5 +
-		    url->maddr_param.slen + 7 +
-		    3 +
-		    url->other_param.slen +
-		    url->header_param.slen;
-    if (size < size_required) {
-	return -1;
-    }
 
     /* Print scheme ("sip:" or "sips:") */
     scheme = pjsip_uri_get_scheme(url);
-    copy_advance_no_check(buf, *scheme);
+    copy_advance_check(buf, *scheme);
     *buf++ = ':';
 
     /* Print "user:password@", if any. */
     if (url->user.slen) {
-	copy_advance_no_check(buf, url->user);
+	copy_advance_escape(buf, url->user, pjsip_USER_SPEC);
 	if (url->passwd.slen) {
 	    *buf++ = ':';
-	    copy_advance_no_check(buf, url->passwd);
+	    copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC);
 	}
 
@@ -162,5 +200,5 @@
     /* Print host. */
     pj_assert(url->host.slen != 0);
-    copy_advance_no_check(buf, url->host);
+    copy_advance_check(buf, url->host);
 
     /* Only print port if it is explicitly specified. 
@@ -171,6 +209,6 @@
      * UA has sent us port, so we'll just send the port indiscrimately
      */
-    PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)
-    if (url->port /*&& context != PJSIP_URI_IN_FROMTO_HDR*/) {
+    //PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)
+    if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) {
 	*buf++ = ':';
 	printed = pj_utoa(url->port, buf);
@@ -179,19 +217,21 @@
 
     /* User param is allowed in all contexes */
-    copy_advance_pair_no_check(buf, ";user=", 6, url->user_param);
+    copy_advance_pair_check(buf, ";user=", 6, url->user_param);
 
     /* Method param is only allowed in external/other context. */
     if (context == PJSIP_URI_IN_OTHER) {
-	copy_advance_pair_no_check(buf, ";method=", 8, url->method_param);
+	copy_advance_pair_escape(buf, ";method=", 8, url->method_param, 
+				 pjsip_PARAM_CHAR_SPEC);
     }
 
     /* Transport is not allowed in From/To header. */
     if (context != PJSIP_URI_IN_FROMTO_HDR) {
-	copy_advance_pair_no_check(buf, ";transport=", 11, url->transport_param);
+	copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
+				 pjsip_PARAM_CHAR_SPEC);
     }
 
     /* TTL param is not allowed in From, To, Route, and Record-Route header. */
     if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
-	context != PJSIP_URI_IN_ROUTING_HDR) 
+	context != PJSIP_URI_IN_ROUTING_HDR && (endbuf-buf) > 15) 
     {
 	pj_memcpy(buf, ";ttl=", 5);
@@ -202,5 +242,6 @@
     /* maddr param is not allowed in From and To header. */
     if (context != PJSIP_URI_IN_FROMTO_HDR) {
-	copy_advance_pair_no_check(buf, ";maddr=", 7, url->maddr_param);
+	copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
+				 pjsip_PARAM_CHAR_SPEC);
     }
 
@@ -210,15 +251,30 @@
     {
 	pj_str_t lr = { ";lr", 3 };
-	copy_advance_no_check(buf, lr);
+	copy_advance_check(buf, lr);
     }
 
     /* Other param. */
-    if (url->other_param.slen) {
-	copy_advance_no_check(buf, url->other_param);
+    param = url->other_param.next;
+    while (param != &url->other_param) {
+	*buf++ = ';';
+	copy_advance_escape(buf, param->name, pjsip_PARAM_CHAR_SPEC);
+	if (param->value.slen) {
+	    *buf++ = '=';
+	    copy_advance_escape(buf, param->value, pjsip_PARAM_CHAR_SPEC);
+	}
+	param = param->next;
     }
 
     /* Header param. */
-    if (url->header_param.slen) {
-	copy_advance_no_check(buf, url->header_param);
+    param = url->header_param.next;
+    while (param != &url->header_param) {
+	*buf++ = hparam_char;
+	copy_advance_escape(buf, param->name, pjsip_HDR_CHAR_SPEC);
+	if (param->value.slen) {
+	    *buf++ = '=';
+	    copy_advance_escape(buf, param->value, pjsip_HDR_CHAR_SPEC);
+	}
+	param = param->next;
+	hparam_char = '&';
     }
 
@@ -227,67 +283,132 @@
 }
 
-static int pjsip_url_compare( pjsip_uri_context_e context,
-			      const pjsip_url *url1, const pjsip_url *url2)
-{
-    /* The easiest (and probably the most efficient) way to compare two URLs
-       are to print them, and compare them bytes per bytes. This technique
-       works quite well with RFC3261, as the RFC (unlike RFC2543) defines that
-       components specified in one URL does NOT match its default value if
-       it is not specified in the second URL. For example, parameter "user=ip"
-       does NOT match if it is omited in second URL.
-
-       HOWEVER, THE SAME CAN NOT BE APPLIED FOR other-param NOR header-param.
-       For these, each of the parameters must be compared one by one. Parameter
-       that exists in one URL will match the comparison. But parameter that
-       exists in both URLs and doesn't match wont match the URL comparison.
-
-       The solution for this is to compare 'standard' URL components with
-       bytes-to-bytes comparison, and compare other-param and header-param with
-       more intelligent comparison.
-     */
-    char str_url1[PJSIP_MAX_URL_SIZE];
-    char str_url2[PJSIP_MAX_URL_SIZE];
-    int len1, len2;
-
-    /* Must compare scheme first, as the second URI may not be SIP URL. */
-    if (pj_stricmp(pjsip_uri_get_scheme(url1), pjsip_uri_get_scheme(url2)))
-	return -1;
-
-    len1 = pjsip_url_print(context, url1, str_url1, sizeof(str_url1));
-    if (len1 < 1) {
-	pj_assert(0);
-	return -1;
-    }
-    len2 = pjsip_url_print(context, url2, str_url2, sizeof(str_url2));
-    if (len2 < 1) {
-	pj_assert(0);
-	return -1;
-    }
-
-    if (len1 != len2) {
-	/* Not equal. */
-	return -1;
-    }
-
-    if (pj_native_strcmp(str_url1, str_url2)) {
-	/* Not equal */
-	return -1;
-    }
-
-    /* TODO: compare other-param and header-param in more intelligent manner. */
-    PJ_TODO(HPARAM_AND_OTHER_PARAM_COMPARISON_IN_URL_COMPARISON)
-
-    if (pj_strcmp(&url1->other_param, &url2->other_param)) {
-	/* Not equal. */
-	return -1;
-    }
-    if (pj_strcmp(&url1->header_param, &url2->header_param)) {
-	/* Not equal. */
-	return -1;
-    }
-
-    /* Seems to be equal, isn't it. */
-    return 0;
+static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
+				      const pjsip_url *url1, 
+				      const pjsip_url *url2)
+{
+    const pjsip_param *p1;
+
+    /*
+     * Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
+     */
+
+    /* SIP and SIPS URI are never equivalent. 
+     * Note: just compare the vptr to avoid string comparison. 
+     *       Pretty neat huh!!
+     */
+    if (url1->vptr != url2->vptr)
+	return PJSIP_ECMPSCHEME;
+
+    /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. 
+     * This includes userinfo containing passwords or formatted as 
+     * telephone-subscribers.
+     */
+    if (pj_strcmp(&url1->user, &url2->user) != 0)
+	return PJSIP_ECMPUSER;
+    if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
+	return PJSIP_ECMPPASSWD;
     
+    /* Comparison of all other components of the URI is
+     * case-insensitive unless explicitly defined otherwise.
+     */
+
+    /* The ordering of parameters and header fields is not significant 
+     * in comparing SIP and SIPS URIs.
+     */
+
+    /* Characters other than those in the reserved set (see RFC 2396 [5])
+     * are equivalent to their encoding.
+     */
+
+    /* An IP address that is the result of a DNS lookup of a host name 
+     * does not match that host name.
+     */
+    if (pj_stricmp(&url1->host, &url2->host) != 0)
+	return PJSIP_ECMPHOST;
+
+    /* A URI omitting any component with a default value will not match a URI
+     * explicitly containing that component with its default value. 
+     * For instance, a URI omitting the optional port component will not match
+     * a URI explicitly declaring port 5060. 
+     * The same is true for the transport-parameter, ttl-parameter, 
+     * user-parameter, and method components.
+     */
+
+    /* Port is not allowed in To and From header.
+     */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (url1->port != url2->port)
+	    return PJSIP_ECMPPORT;
+    }
+    /* Transport is not allowed in From/To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0)
+	    return PJSIP_ECMPTRANSPORTPRM;
+    }
+    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR &&
+	context != PJSIP_URI_IN_ROUTING_HDR)
+    {
+	if (url1->ttl_param != url2->ttl_param)
+	    return PJSIP_ECMPTTLPARAM;
+    }
+    /* User param is allowed in all contexes */
+    if (pj_stricmp(&url1->user_param, &url2->user_param) != 0)
+	return PJSIP_ECMPUSERPARAM;
+    /* Method param is only allowed in external/other context. */
+    if (context == PJSIP_URI_IN_OTHER) {
+	if (pj_stricmp(&url1->method_param, &url2->method_param) != 0)
+	    return PJSIP_ECMPMETHODPARAM;
+    }
+    /* maddr param is not allowed in From and To header. */
+    if (context != PJSIP_URI_IN_FROMTO_HDR) {
+	if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0)
+	    return PJSIP_ECMPMADDRPARAM;
+    }
+
+    /* lr parameter is ignored (?) */
+    /* lr param is not allowed in From, To, and Contact header. */
+
+
+    /* All other uri-parameters appearing in only one URI are ignored when 
+     * comparing the URIs.
+     */
+    p1 = url1->other_param.next;
+    while (p1 != &url1->other_param) {
+	const pjsip_param *p2;
+	p2 = pjsip_param_cfind(&url2->other_param, &p1->name);
+	if (p2 ) {
+	    if (pj_stricmp(&p1->value, &p2->value) != 0)
+		return PJSIP_ECMPOTHERPARAM;
+	}
+
+	p1 = p1->next;
+    }
+
+    /* URI header components are never ignored. Any present header component
+     * MUST be present in both URIs and match for the URIs to match. 
+     * The matching rules are defined for each header field in Section 20.
+     */
+    p1 = url1->header_param.next;
+    while (p1 != &url1->header_param) {
+	const pjsip_param *p2;
+	p2 = pjsip_param_cfind(&url2->header_param, &p1->name);
+	if (p2) {
+	    /* It seems too much to compare two header params according to
+	     * the rule of each header. We'll just compare them string to
+	     * string..
+	     */
+	    PJ_TODO(MORE_COMPLIANT_HEADER_PARAM_COMPARISON_IN_URL);
+
+	    if (pj_stricmp(&p1->value, &p2->value) != 0)
+		return PJSIP_ECMPHEADERPARAM;
+	} else {
+	    return PJSIP_ECMPHEADERPARAM;
+	}
+	p1 = p1->next;
+    }
+
+    /* Equal!! Pheuww.. */
+    return PJ_SUCCESS;
 }
 
@@ -305,6 +426,6 @@
     url->ttl_param = rhs->ttl_param;
     pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
-    pj_strdup( pool, &url->other_param, &rhs->other_param);
-    pj_strdup( pool, &url->header_param, &rhs->header_param);
+    pjsip_param_clone(pool, &url->other_param, &rhs->other_param);
+    pjsip_param_clone(pool, &url->header_param, &rhs->header_param);
     url->lr_param = rhs->lr_param;
 }
Index: pjproject/trunk/pjsip/src/pjsip/sip_util.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 64)
+++ pjproject/trunk/pjsip/src/pjsip/sip_util.c	(revision 64)
@@ -0,0 +1,724 @@
+/* $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_util.h>
+#include <pjsip/sip_transport.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_transaction.h>
+#include <pjsip/sip_module.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/pool.h>
+#include <pj/except.h>
+#include <pj/rand.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#define THIS_FILE    "endpoint"
+
+static const char *event_str[] = 
+{
+    "UNIDENTIFIED",
+    "TIMER",
+    "TX_MSG",
+    "RX_MSG",
+    "TRANSPORT_ERROR",
+    "TSX_STATE",
+    "RX_2XX_RESPONSE",
+    "RX_ACK",
+    "DISCARD_MSG",
+    "USER",
+    "BEFORE_TX",
+};
+
+static pj_str_t str_TEXT = { "text", 4},
+		str_PLAIN = { "plain", 5 };
+static int aux_mod_id;
+
+struct aux_tsx_data
+{
+    void *token;
+    void (*cb)(void*,pjsip_event*);
+};
+
+static pj_status_t aux_tsx_init( pjsip_endpoint *endpt,
+				 struct pjsip_module *mod, pj_uint32_t id )
+{
+    PJ_UNUSED_ARG(endpt);
+    PJ_UNUSED_ARG(mod);
+
+    aux_mod_id = id;
+    return 0;
+}
+
+static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
+{
+    pjsip_transaction *tsx;
+    struct aux_tsx_data *tsx_data;
+
+    PJ_UNUSED_ARG(mod);
+
+    if (event->type != PJSIP_EVENT_TSX_STATE)
+	return;
+
+    pj_assert(event->body.tsx_state.tsx != NULL);
+    tsx = event->body.tsx_state.tsx;
+    if (tsx == NULL)
+	return;
+    if (tsx->module_data[aux_mod_id] == NULL)
+	return;
+    if (tsx->status_code < 200)
+	return;
+
+    /* Call the callback, if any, and prevent the callback to be called again
+     * by clearing the transaction's module_data.
+     */
+    tsx_data = tsx->module_data[aux_mod_id];
+    tsx->module_data[aux_mod_id] = NULL;
+
+    if (tsx_data->cb) {
+	(*tsx_data->cb)(tsx_data->token, event);
+    }
+}
+
+pjsip_module aux_tsx_module = 
+{
+    { "Aux-Tsx", 7},	    /* Name.		*/
+    0,			    /* Flag		*/
+    128,		    /* Priority		*/
+    NULL,		    /* Arbitrary data.	*/
+    0,			    /* Number of methods supported (none). */
+    { 0 },		    /* Array of methods (none) */
+    &aux_tsx_init,	    /* init_module()	*/
+    NULL,		    /* start_module()	*/
+    NULL,		    /* deinit_module()	*/
+    &aux_tsx_handler,	    /* tsx_handler()	*/
+};
+
+PJ_DEF(pj_status_t) pjsip_endpt_send_request(  pjsip_endpoint *endpt,
+					       pjsip_tx_data *tdata,
+					       int timeout,
+					       void *token,
+					       void (*cb)(void*,pjsip_event*))
+{
+    pjsip_transaction *tsx;
+    struct aux_tsx_data *tsx_data;
+    pj_status_t status;
+
+    status = pjsip_endpt_create_tsx(endpt, &tsx);
+    if (!tsx) {
+	pjsip_tx_data_dec_ref(tdata);
+	return -1;
+    }
+
+    tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data));
+    tsx_data->token = token;
+    tsx_data->cb = cb;
+    tsx->module_data[aux_mod_id] = tsx_data;
+
+    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {
+	pjsip_endpt_destroy_tsx(endpt, tsx);
+	pjsip_tx_data_dec_ref(tdata);
+	return -1;
+    }
+
+    pjsip_endpt_register_tsx(endpt, tsx);
+    pjsip_tx_data_invalidate_msg(tdata);
+    pjsip_tsx_on_tx_msg(tsx, tdata);
+    pjsip_tx_data_dec_ref(tdata);
+    return 0;
+}
+
+/*
+ * Initialize transmit data (msg) with the headers and optional body.
+ * This will just put the headers in the message as it is. Be carefull
+ * when calling this function because once a header is put in a message, 
+ * it CAN NOT be put in other message until the first message is deleted, 
+ * because the way the header is put in the list.
+ * That's why the session will shallow_clone it's headers before calling
+ * this function.
+ */
+static void init_request_throw( pjsip_endpoint *endpt,
+                                pjsip_tx_data *tdata, 
+				pjsip_method *method,
+				pjsip_uri *param_target,
+				pjsip_from_hdr *param_from,
+				pjsip_to_hdr *param_to, 
+				pjsip_contact_hdr *param_contact,
+				pjsip_cid_hdr *param_call_id,
+				pjsip_cseq_hdr *param_cseq, 
+				const pj_str_t *param_text)
+{
+    pjsip_msg *msg;
+    pjsip_msg_body *body;
+    const pjsip_hdr *endpt_hdr;
+
+    /* Create the message. */
+    msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
+
+    /* Init request URI. */
+    pj_memcpy(&msg->line.req.method, method, sizeof(*method));
+    msg->line.req.uri = param_target;
+
+    /* Add additional request headers from endpoint. */
+    endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next;
+    while (endpt_hdr != pjsip_endpt_get_request_headers(endpt)) {
+	pjsip_hdr *hdr = pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr);
+	pjsip_msg_add_hdr( tdata->msg, hdr );
+	endpt_hdr = endpt_hdr->next;
+    }
+
+    /* Add From header. */
+    if (param_from->tag.slen == 0)
+	pj_create_unique_string(tdata->pool, &param_from->tag);
+    pjsip_msg_add_hdr(msg, (void*)param_from);
+
+    /* Add To header. */
+    pjsip_msg_add_hdr(msg, (void*)param_to);
+
+    /* Add Contact header. */
+    if (param_contact) {
+	pjsip_msg_add_hdr(msg, (void*)param_contact);
+    }
+
+    /* Add Call-ID header. */
+    pjsip_msg_add_hdr(msg, (void*)param_call_id);
+
+    /* Add CSeq header. */
+    pjsip_msg_add_hdr(msg, (void*)param_cseq);
+
+    /* Create message body. */
+    if (param_text) {
+	body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body));
+	body->content_type.type = str_TEXT;
+	body->content_type.subtype = str_PLAIN;
+	body->data = pj_pool_alloc(tdata->pool, param_text->slen );
+	pj_memcpy(body->data, param_text->ptr, param_text->slen);
+	body->len = param_text->slen;
+	body->print_body = &pjsip_print_text_body;
+	msg->body = body;
+    }
+}
+
+/*
+ * Create arbitrary request.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_request(  pjsip_endpoint *endpt, 
+						 const pjsip_method *method,
+						 const pj_str_t *param_target,
+						 const pj_str_t *param_from,
+						 const pj_str_t *param_to, 
+						 const pj_str_t *param_contact,
+						 const pj_str_t *param_call_id,
+						 int param_cseq, 
+						 const pj_str_t *param_text,
+						 pjsip_tx_data **p_tdata)
+{
+    pjsip_uri *target;
+    pjsip_tx_data *tdata;
+    pjsip_from_hdr *from;
+    pjsip_to_hdr *to;
+    pjsip_contact_hdr *contact;
+    pjsip_cseq_hdr *cseq = NULL;    /* = NULL, warning in VC6 */
+    pjsip_cid_hdr *call_id;
+    pj_str_t tmp;
+    pj_status_t status;
+    PJ_USE_EXCEPTION;
+
+    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()"));
+
+    status = pjsip_endpt_create_tdata(endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init reference counter to 1. */
+    pjsip_tx_data_add_ref(tdata);
+
+    PJ_TRY {
+	/* Request target. */
+	pj_strdup_with_null(tdata->pool, &tmp, param_target);
+	target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0);
+	if (target == NULL) {
+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid target %s", 
+		      tmp.ptr));
+	    goto on_error;
+	}
+
+	/* From */
+	from = pjsip_from_hdr_create(tdata->pool);
+	pj_strdup_with_null(tdata->pool, &tmp, param_from);
+	from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
+				     PJSIP_PARSE_URI_AS_NAMEADDR);
+	if (from->uri == NULL) {
+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'",
+				tmp.ptr));
+	    goto on_error;
+	}
+	pj_create_unique_string(tdata->pool, &from->tag);
+
+	/* To */
+	to = pjsip_to_hdr_create(tdata->pool);
+	pj_strdup_with_null(tdata->pool, &tmp, param_to);
+	to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
+				   PJSIP_PARSE_URI_AS_NAMEADDR);
+	if (to->uri == NULL) {
+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'",
+				tmp.ptr));
+	    goto on_error;
+	}
+
+	/* Contact. */
+	if (param_contact) {
+	    contact = pjsip_contact_hdr_create(tdata->pool);
+	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);
+	    contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen,
+					    PJSIP_PARSE_URI_AS_NAMEADDR);
+	    if (contact->uri == NULL) {
+		PJ_LOG(4,(THIS_FILE, 
+			  "Error creating request: invalid 'Contact' URI '%s'",
+			  tmp.ptr));
+		goto on_error;
+	    }
+	} else {
+	    contact = NULL;
+	}
+
+	/* Call-ID */
+	call_id = pjsip_cid_hdr_create(tdata->pool);
+	if (param_call_id != NULL && param_call_id->slen)
+	    pj_strdup(tdata->pool, &call_id->id, param_call_id);
+	else
+	    pj_create_unique_string(tdata->pool, &call_id->id);
+
+	/* CSeq */
+	cseq = pjsip_cseq_hdr_create(tdata->pool);
+	if (param_cseq >= 0)
+	    cseq->cseq = param_cseq;
+	else
+	    cseq->cseq = pj_rand() & 0xFFFF;
+
+	/* Method */
+	pjsip_method_copy(tdata->pool, &cseq->method, method);
+
+	/* Create the request. */
+	init_request_throw( endpt, tdata, &cseq->method, target, from, to, 
+                            contact, call_id, cseq, param_text);
+    }
+    PJ_DEFAULT {
+	status = PJ_ENOMEM;
+	goto on_error;
+    }
+    PJ_END
+
+    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
+		        tdata->obj_name, 
+			cseq->cseq, 
+			cseq->method.name.slen,
+			cseq->method.name.ptr));
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+
+on_error:
+    pjsip_tx_data_dec_ref(tdata);
+    return status;
+}
+
+PJ_DEF(pj_status_t)
+pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
+				     const pjsip_method *method,
+				     const pjsip_uri *param_target,
+				     const pjsip_from_hdr *param_from,
+				     const pjsip_to_hdr *param_to,
+				     const pjsip_contact_hdr *param_contact,
+				     const pjsip_cid_hdr *param_call_id,
+				     int param_cseq,
+				     const pj_str_t *param_text,
+				     pjsip_tx_data **p_tdata)
+{
+    pjsip_uri *target;
+    pjsip_tx_data *tdata;
+    pjsip_from_hdr *from;
+    pjsip_to_hdr *to;
+    pjsip_contact_hdr *contact;
+    pjsip_cid_hdr *call_id;
+    pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */
+    pj_status_t status;
+    PJ_USE_EXCEPTION;
+
+    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()"));
+
+    status = pjsip_endpt_create_tdata(endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pjsip_tx_data_add_ref(tdata);
+
+    PJ_TRY {
+	target = pjsip_uri_clone(tdata->pool, param_target);
+	from = pjsip_hdr_shallow_clone(tdata->pool, param_from);
+	pjsip_fromto_set_from(from);
+	to = pjsip_hdr_shallow_clone(tdata->pool, param_to);
+	pjsip_fromto_set_to(to);
+	if (param_contact)
+	    contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact);
+	else
+	    contact = NULL;
+	call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id);
+	cseq = pjsip_cseq_hdr_create(tdata->pool);
+	if (param_cseq >= 0)
+	    cseq->cseq = param_cseq;
+	else
+	    cseq->cseq = pj_rand() % 0xFFFF;
+	pjsip_method_copy(tdata->pool, &cseq->method, method);
+
+	init_request_throw(endpt, tdata, &cseq->method, target, from, to, 
+                           contact, call_id, cseq, param_text);
+    }
+    PJ_DEFAULT {
+	status = PJ_ENOMEM;
+	goto on_error;
+    }
+    PJ_END;
+
+    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
+			tdata->obj_name, 
+			cseq->cseq, 
+			cseq->method.name.slen,
+			cseq->method.name.ptr));
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+
+on_error:
+    pjsip_tx_data_dec_ref(tdata);
+    return status;
+}
+
+/*
+ * Construct a minimal response message for the received request.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
+						 const pjsip_rx_data *rdata,
+						 int code,
+						 pjsip_tx_data **p_tdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_msg *msg, *req_msg;
+    pjsip_hdr *hdr;
+    pjsip_via_hdr *via;
+    pjsip_rr_hdr *rr;
+    pj_status_t status;
+
+    /* rdata must be a request message. */
+    req_msg = rdata->msg_info.msg;
+    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);
+
+    /* Log this action. */
+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", 
+		         rdata, code));
+
+    /* Create a new transmit buffer. */
+    status = pjsip_endpt_create_tdata( endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create new response message. */
+    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);
+
+    /* Set status code and reason text. */
+    msg->line.status.code = code;
+    msg->line.status.reason = *pjsip_get_status_text(code);
+
+    /* Set TX data attributes. */
+    tdata->rx_timestamp = rdata->pkt_info.timestamp;
+
+    /* Copy all the via headers, in order. */
+    via = rdata->msg_info.via;
+    while (via) {
+	pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via));
+	via = via->next;
+	if (via != (void*)&req_msg->hdr)
+	    via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);
+	else
+	    break;
+    }
+
+    /* Copy all Record-Route headers, in order. */
+    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);
+    while (rr) {
+	pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr));
+	rr = rr->next;
+	if (rr != (void*)&req_msg->hdr)
+	    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr);
+	else
+	    break;
+    }
+
+    /* Copy Call-ID header. */
+    hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);
+    pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr));
+
+    /* Copy From header. */
+    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from);
+    pjsip_msg_add_hdr( msg, hdr);
+
+    /* Copy To header. */
+    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to);
+    pjsip_msg_add_hdr( msg, hdr);
+
+    /* Copy CSeq header. */
+    hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq);
+    pjsip_msg_add_hdr( msg, hdr);
+
+    /* All done. */
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of
+ * RFC3261). Note that the generation of ACK for 2xx response is different,
+ * and one must not use this function to generate such ACK.
+ */
+PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,
+				    pjsip_tx_data *tdata,
+				    const pjsip_rx_data *rdata )
+{
+    pjsip_msg *ack_msg, *invite_msg;
+    pjsip_to_hdr *to;
+    pjsip_from_hdr *from;
+    pjsip_cseq_hdr *cseq;
+    pjsip_hdr *hdr;
+
+    /* Make compiler happy. */
+    PJ_UNUSED_ARG(endpt);
+
+    /* rdata must be a final response. */
+    pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG &&
+	      rdata->msg_info.msg->line.status.code >= 300);
+
+    /* Log this action. */
+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata));
+
+    /* Create new request message. */
+    ack_msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
+    pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD );
+
+    /* The original INVITE message. */
+    invite_msg = tdata->msg;
+
+    /* Copy Request-Uri from the original INVITE. */
+    ack_msg->line.req.uri = invite_msg->line.req.uri;
+    
+    /* Copy Call-ID from the original INVITE */
+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL);
+    pjsip_msg_add_hdr( ack_msg, hdr );
+
+    /* Copy From header from the original INVITE. */
+    from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, 
+						      PJSIP_H_FROM, NULL);
+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from );
+
+    /* Copy To header from the original INVITE. */
+    to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg, 
+						   PJSIP_H_TO, NULL);
+    pj_strdup(tdata->pool, &to->tag, &rdata->msg_info.to->tag);
+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to );
+
+    /* Must contain single Via, just as the original INVITE. */
+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL);
+    pjsip_msg_insert_first_hdr( ack_msg, hdr );
+
+    /* Must have the same CSeq value as the original INVITE, but method 
+     * changed to ACK 
+     */
+    cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, 
+							PJSIP_H_CSEQ, NULL);
+    pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD );
+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq );
+
+    /* If the original INVITE has Route headers, those header fields MUST 
+     * appear in the ACK.
+     */
+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
+    while (hdr != NULL) {
+	pjsip_msg_add_hdr( ack_msg, hdr );
+	hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
+    }
+
+    /* Set the message in the "tdata" to point to the ACK message. */
+    tdata->msg = ack_msg;
+
+    /* Reset transmit packet buffer, to force 're-printing' of message. */
+    tdata->buf.cur = tdata->buf.start;
+
+    /* We're done.
+     * "tdata" parameter now contains the ACK message.
+     */
+}
+
+
+/*
+ * Construct CANCEL request for the previously sent request, according to
+ * chapter 9.1 of RFC3261.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
+					       pjsip_tx_data *req_tdata,
+					       pjsip_tx_data **p_tdata)
+{
+    pjsip_msg *req_msg;	/* the original request. */
+    pjsip_tx_data *cancel_tdata;
+    pjsip_msg *cancel_msg;
+    pjsip_hdr *hdr;
+    pjsip_cseq_hdr *req_cseq, *cseq;
+    pjsip_uri *req_uri;
+    pj_status_t status;
+
+    /* Log this action. */
+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata));
+
+    /* Get the original request. */
+    req_msg = req_tdata->msg;
+
+    /* The transmit buffer must INVITE request. */
+    PJ_ASSERT_RETURN(req_msg->type == PJSIP_REQUEST_MSG &&
+		     req_msg->line.req.method.id == PJSIP_INVITE_METHOD,
+		     PJ_EINVAL);
+
+    /* Create new transmit buffer. */
+    status = pjsip_endpt_create_tdata( endpt, &cancel_tdata);
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
+
+    /* Create CANCEL request message. */
+    cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG);
+    cancel_tdata->msg = cancel_msg;
+
+    /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are
+     * copied from the original request.
+     */
+    /* Set request line. */
+    pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD);
+    req_uri = req_msg->line.req.uri;
+    cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri);
+
+    /* Copy Call-ID */
+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL);
+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
+
+    /* Copy From header. */
+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL);
+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
+
+    /* Copy To header. */
+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL);
+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
+
+    /* Create new CSeq with equal number, but method set to CANCEL. */
+    req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL);
+    cseq = pjsip_cseq_hdr_create(cancel_tdata->pool);
+    cseq->cseq = req_cseq->cseq;
+    pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD);
+    pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq);
+
+    /* Must only have single Via which matches the top-most Via in the 
+     * request being cancelled. 
+     */
+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL);
+    pjsip_msg_insert_first_hdr(cancel_msg, 
+			       pjsip_hdr_clone(cancel_tdata->pool, hdr));
+
+    /* If the original request has Route header, the CANCEL request must also
+     * has exactly the same.
+     * Copy "Route" header from the request.
+     */
+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL);
+    while (hdr != NULL) {
+	pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
+	hdr = hdr->next;
+	if (hdr != &cancel_msg->hdr)
+	    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr);
+	else
+	    break;
+    }
+
+    /* Done.
+     * Return the transmit buffer containing the CANCEL request.
+     */
+    *p_tdata = cancel_tdata;
+    return PJ_SUCCESS;
+}
+
+/* Get the address parameters (host, port, flag, TTL, etc) to send the
+ * response.
+ */
+PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
+					    const pjsip_transport *req_transport,
+					    const pjsip_via_hdr *via,
+					    pjsip_host_port *send_addr)
+{
+    /* Determine the destination address (section 18.2.2):
+     * - for TCP, SCTP, or TLS, send the response using the transport where
+     *   the request was received.
+     * - if maddr parameter is present, send to this address using the port
+     *   in sent-by or 5060. If multicast is used, the TTL in the Via must
+     *   be used, or 1 if ttl parameter is not present.
+     * - otherwise if received parameter is present, set to this address.
+     * - otherwise send to the address in sent-by.
+     */
+    send_addr->flag = req_transport->flag;
+    send_addr->type = req_transport->type;
+
+    if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) {
+	const pj_sockaddr_in *remote_addr;
+	remote_addr = &req_transport->rem_addr;
+	pj_strdup2(pool, &send_addr->host, 
+		   pj_inet_ntoa(remote_addr->sin_addr));
+	send_addr->port = pj_sockaddr_in_get_port(remote_addr);
+
+    } else {
+	/* Set the host part */
+	if (via->maddr_param.slen) {
+	    pj_strdup(pool, &send_addr->host, &via->maddr_param);
+	} else if (via->recvd_param.slen) {
+	    pj_strdup(pool, &send_addr->host, &via->recvd_param);
+	} else {
+	    pj_strdup(pool, &send_addr->host, &via->sent_by.host);
+	}
+
+	/* Set the port */
+	send_addr->port = via->sent_by.port;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Get the event string from the event ID.
+ */
+PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)
+{
+    return event_str[e];
+}
+
Index: pjproject/trunk/pjsip/src/test-pjsip/main.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/main.c	(revision 63)
+++ pjproject/trunk/pjsip/src/test-pjsip/main.c	(revision 64)
@@ -17,2 +17,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
+#include "test.h"
+
+int main(void)
+{
+    return test_main();
+}
Index: pjproject/trunk/pjsip/src/test-pjsip/msg.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/msg.c	(revision 64)
+++ pjproject/trunk/pjsip/src/test-pjsip/msg.c	(revision 64)
@@ -0,0 +1,369 @@
+/* $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_core.h>
+#include <pjlib.h>
+
+static pjsip_msg *create_msg0(pj_pool_t *pool);
+
+struct test_msg
+{
+    char	 msg[1024];
+    pjsip_msg *(*creator)(pj_pool_t *pool);
+    pj_size_t	 len;
+} test_array[] = 
+{
+    {
+	/* 'Normal' message with all headers. */
+	"INVITE sip:user@foo SIP/2.0\n"
+	"From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r"
+	"To: Fellow User <sip:user@foo.bar.domain.com>\r\n"
+	"Call-ID: 12345678901234567890@bar\r\n"
+	"Content-Length: 0\r\n"
+	"CSeq: 123456 INVITE\n"
+	"Contact: <sip:joe@bar> ; q=0.5;expires=3600,sip:user@host;q=0.500\r"
+	"  ,sip:user2@host2\n"
+	"Content-Type: text/html ; charset=ISO-8859-4\r"
+	"Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n"
+	"  <sip:server10.biloxi.com;lr>\r"
+	"Record-Route: <sip:server10.biloxi.com>,\r\n"
+	"  <sip:bigbox3.site3.atlanta.com;lr>\n"
+	"Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n"
+	"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
+	" ;received=192.0.2.1\r\n"
+	"Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n"
+	"Organization: \r"
+	"Max-Forwards: 70\n"
+	"X-Header: \r\n"
+	"\r",
+	&create_msg0
+    }
+};
+
+static pj_uint32_t parse_len, parse_time, print_time;
+
+static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry )
+{
+    pjsip_msg *parsed_msg, *ref_msg;
+    pj_status_t status = PJ_SUCCESS;
+    int len;
+    pj_str_t str1, str2;
+    pjsip_hdr *hdr1, *hdr2;
+    pj_timestamp t1, t2;
+    char *msgbuf;
+
+    enum { BUFLEN = 512 };
+    
+    /* Parse message. */
+    parse_len += entry->len;
+    pj_get_timestamp(&t1);
+    parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL);
+    if (parsed_msg == NULL) {
+	status = -10;
+	goto on_return;
+    }
+    pj_get_timestamp(&t2);
+    parse_time += t2.u32.lo - t1.u32.lo;
+
+    /* Create reference message. */
+    ref_msg = entry->creator(pool);
+
+    /* Create buffer for comparison. */
+    str1.ptr = pj_pool_alloc(pool, BUFLEN);
+    str2.ptr = pj_pool_alloc(pool, BUFLEN);
+
+    /* Compare message type. */
+    if (parsed_msg->type != ref_msg->type) {
+	status = -20;
+	goto on_return;
+    }
+
+    /* Compare request or status line. */
+    if (parsed_msg->type == PJSIP_REQUEST_MSG) {
+	pjsip_method *m1 = &parsed_msg->line.req.method;
+	pjsip_method *m2 = &ref_msg->line.req.method;
+
+	if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) {
+	    status = -30;
+	    goto on_return;
+	}
+    } else {
+
+    }
+
+    /* Compare headers. */
+    hdr1 = parsed_msg->hdr.next;
+    hdr2 = ref_msg->hdr.next;
+
+    while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) {
+	len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN);
+	if (len < 1) {
+	    status = -40;
+	    goto on_return;
+	}
+	str1.slen = len;
+
+	len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN);
+	if (len < 1) {
+	    status = -50;
+	    goto on_return;
+	}
+	str2.slen = len;
+
+	if (pj_strcmp(&str1, &str2) != 0) {
+	    status = -60;
+	    goto on_return;
+	}
+
+	hdr1 = hdr1->next;
+	hdr2 = hdr2->next;
+    }
+
+    if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) {
+	status = -70;
+	goto on_return;
+    }
+
+    /* Print message. */
+    msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN);
+    if (msgbuf == NULL) {
+	status = -80;
+	goto on_return;
+    }
+    pj_get_timestamp(&t1);
+    len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN);
+    if (len < 1) {
+	status = -90;
+	goto on_return;
+    }
+    pj_get_timestamp(&t2);
+    print_time += t2.u32.lo - t1.u32.lo;
+    status = PJ_SUCCESS;
+
+on_return:
+    return status;
+}
+
+
+pj_status_t msg_test(void)
+{
+    pj_status_t status;
+    pj_pool_t *pool;
+
+    pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
+
+    status = test_entry( pool, &test_array[0] );
+
+    pjsip_endpt_destroy(endpt);
+    return status;
+}
+
+/*****************************************************************************/
+
+static pjsip_msg *create_msg0(pj_pool_t *pool)
+{
+
+    pjsip_msg *msg;
+    pjsip_name_addr *name_addr;
+    pjsip_url *url;
+    pjsip_fromto_hdr *fromto;
+    pjsip_cid_hdr *cid;
+    pjsip_clen_hdr *clen;
+    pjsip_cseq_hdr *cseq;
+    pjsip_contact_hdr *contact;
+    pjsip_ctype_hdr *ctype;
+    pjsip_routing_hdr *routing;
+    pjsip_via_hdr *via;
+    pjsip_generic_string_hdr *generic;
+    pj_str_t str;
+
+    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);
+
+    /* "INVITE sip:user@foo SIP/2.0\n" */
+    pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
+    url = pjsip_url_create(pool, 0);
+    msg->line.req.uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "user");
+    pj_strdup2(pool, &url->host, "foo");
+
+    /* "From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r" */
+    fromto = pjsip_from_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
+    pj_strdup2(pool, &fromto->tag, "1234578901234567890");
+    name_addr = pjsip_name_addr_create(pool);
+    fromto->uri = (pjsip_uri*)name_addr;
+    pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "joe.user");
+    pj_strdup2(pool, &url->host, "bar.otherdomain.com");
+
+    /* "To: Fellow User <sip:user@foo.bar.domain.com>\r\n" */
+    fromto = pjsip_to_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
+    name_addr = pjsip_name_addr_create(pool);
+    fromto->uri = (pjsip_uri*)name_addr;
+    pj_strdup2(pool, &name_addr->display, "Fellow User");
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "user");
+    pj_strdup2(pool, &url->host, "foo.bar.domain.com");
+
+    /* "Call-ID: 12345678901234567890@bar\r\n" */
+    cid = pjsip_cid_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid);
+    pj_strdup2(pool, &cid->id, "12345678901234567890@bar");
+
+    /* "Content-Length: 0\r\n" */
+    clen = pjsip_clen_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen);
+    clen->len = 0;
+
+    /* "CSeq: 123456 INVITE\n" */
+    cseq = pjsip_cseq_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq);
+    cseq->cseq = 123456;
+    pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD);
+
+    /* "Contact: <sip:joe@bar>;q=0.5;expires=3600*/
+    contact = pjsip_contact_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
+    contact->q1000 = 500;
+    contact->expires = 3600;
+    name_addr = pjsip_name_addr_create(pool);
+    contact->uri = (pjsip_uri*)name_addr;
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "joe");
+    pj_strdup2(pool, &url->host, "bar");
+
+    /*, sip:user@host;q=0.500\r" */
+    contact = pjsip_contact_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
+    contact->q1000 = 500;
+    url = pjsip_url_create(pool, 0);
+    contact->uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "user");
+    pj_strdup2(pool, &url->host, "host");
+
+    /* "  ,sip:user2@host2\n" */
+    contact = pjsip_contact_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
+    url = pjsip_url_create(pool, 0);
+    contact->uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->user, "user2");
+    pj_strdup2(pool, &url->host, "host2");
+
+    /* "Content-Type: text/html; charset=ISO-8859-4\r" */
+    ctype = pjsip_ctype_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype);
+    pj_strdup2(pool, &ctype->media.type, "text");
+    pj_strdup2(pool, &ctype->media.subtype, "html");
+    pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4");
+
+    /* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
+    routing = pjsip_route_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
+    url = pjsip_url_create(pool, 0);
+    routing->name_addr.uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
+    url->lr_param = 1;
+
+    /* "  <sip:server10.biloxi.com;lr>\r" */
+    routing = pjsip_route_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
+    url = pjsip_url_create(pool, 0);
+    routing->name_addr.uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->host, "server10.biloxi.com");
+    url->lr_param = 1;
+
+    /* "Record-Route: <sip:server10.biloxi.com>,\r\n" */
+    routing = pjsip_rr_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
+    url = pjsip_url_create(pool, 0);
+    routing->name_addr.uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->host, "server10.biloxi.com");
+    url->lr_param = 0;
+
+    /* "  <sip:bigbox3.site3.atlanta.com;lr>\n" */
+    routing = pjsip_rr_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
+    url = pjsip_url_create(pool, 0);
+    routing->name_addr.uri = (pjsip_uri*)url;
+    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
+    url->lr_param = 1;
+
+    /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */
+    via = pjsip_via_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
+    pj_strdup2(pool, &via->transport, "SCTP");
+    pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com");
+    pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1");
+
+    /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
+	" ;received=192.0.2.1\r\n" */
+    via = pjsip_via_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
+    pj_strdup2(pool, &via->transport, "UDP");
+    pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com");
+    pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8");
+    pj_strdup2(pool, &via->recvd_param, "192.0.2.1");
+
+
+    /* "Via: SIP/2.0/UDP 10.2.1.1, */ 
+    via = pjsip_via_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
+    pj_strdup2(pool, &via->transport, "UDP");
+    pj_strdup2(pool, &via->sent_by.host, "10.2.1.1");
+    
+    
+    /*SIP/2.0/TCP 192.168.1.1\n" */
+    via = pjsip_via_hdr_create(pool);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
+    pj_strdup2(pool, &via->transport, "TCP");
+    pj_strdup2(pool, &via->sent_by.host, "192.168.1.1");
+
+    /* "Organization: \r" */
+    str.ptr = "Organization";
+    str.slen = 12;
+    generic = pjsip_generic_string_hdr_create(pool, &str);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
+    generic->hvalue.ptr = NULL;
+    generic->hvalue.slen = 0;
+
+    /* "Max-Forwards: 70\n" */
+    str.ptr = "Max-Forwards";
+    str.slen = 12;
+    generic = pjsip_generic_string_hdr_create(pool, &str);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
+    str.ptr = "70";
+    str.slen = 2;
+    generic->hvalue = str;
+
+    /* "X-Header: \r\n" */
+    str.ptr = "X-Header";
+    str.slen = 8;
+    generic = pjsip_generic_string_hdr_create(pool, &str);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
+    str.ptr = NULL;
+    str.slen = 0;
+    generic->hvalue = str;
+
+    return msg;
+}
Index: pjproject/trunk/pjsip/src/test-pjsip/parse_msg.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/parse_msg.c	(revision 63)
+++ 	(revision )
@@ -1,440 +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/sip_msg.h>
-#include <pjsip/sip_parser.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "test.h"
-
-#define ERR_SYNTAX_ERR	(-2)
-#define ERR_NOT_EQUAL	(-3)
-#define ERR_SYSTEM	(-4)
-
-
-static pjsip_msg *create_msg0(pj_pool_t *pool);
-
-struct test_msg
-{
-    char	 msg[1024];
-    pjsip_msg *(*creator)(pj_pool_t *pool);
-    pj_size_t	 len;
-} test_array[] = 
-{
-    {
-	/* 'Normal' message with all headers. */
-	"INVITE sip:user@foo SIP/2.0\n"
-	"From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r"
-	"To: Fellow User <sip:user@foo.bar.domain.com>\r\n"
-	"Call-ID: 12345678901234567890@bar\r\n"
-	"Content-Length: 0\r\n"
-	"CSeq: 123456 INVITE\n"
-	"Contact: <sip:joe@bar> ; q=0.5;expires=3600,sip:user@host;q=0.500\r"
-	"  ,sip:user2@host2\n"
-	"Content-Type: text/html ; charset=ISO-8859-4\r"
-	"Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n"
-	"  <sip:server10.biloxi.com;lr>\r"
-	"Record-Route: <sip:server10.biloxi.com>,\r\n"
-	"  <sip:bigbox3.site3.atlanta.com;lr>\n"
-	"Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n"
-	"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
-	" ;received=192.0.2.1\r\n"
-	"Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n"
-	"Organization: \r"
-	"Max-Forwards: 70\n"
-	"X-Header: \r\n"
-	"\r",
-	&create_msg0
-    }
-};
-
-static pj_caching_pool cp;
-static pj_pool_factory *pf = &cp.factory;
-static pj_uint32_t parse_len, parse_time, print_time;
-
-static void pool_error(pj_pool_t *pool, pj_size_t sz)
-{
-    PJ_UNUSED_ARG(pool)
-    PJ_UNUSED_ARG(sz)
-
-    pj_assert(0);
-    exit(1);
-}
-
-static const char *STATUS_STR(pj_status_t status)
-{
-    switch (status) {
-    case 0: return "OK";
-    case ERR_SYNTAX_ERR: return "Syntax Error";
-    case ERR_NOT_EQUAL: return "Not Equal";
-    case ERR_SYSTEM: return "System Error";
-    }
-    return "???";
-}
-
-static pj_status_t test_entry( struct test_msg *entry )
-{
-    pjsip_msg *parsed_msg, *ref_msg;
-    pj_pool_t *pool;
-    pj_status_t status = PJ_SUCCESS;
-    int len;
-    pj_str_t str1, str2;
-    pjsip_hdr *hdr1, *hdr2;
-    pj_hr_timestamp t1, t2;
-    char *msgbuf;
-
-    enum { BUFLEN = 512 };
-    
-    pool = pj_pool_create( pf, "", 
-			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 
-			   &pool_error);
-
-    if (entry->len == 0) {
-	entry->len = strlen(entry->msg);
-    }
-
-    /* Parse message. */
-    parse_len += entry->len;
-    pj_hr_gettimestamp(&t1);
-    parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL);
-    if (parsed_msg == NULL) {
-	status = ERR_SYNTAX_ERR;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    parse_time += t2.u32.lo - t1.u32.lo;
-
-#if IS_PROFILING
-    goto print_msg;
-#endif
-
-    /* Create reference message. */
-    ref_msg = entry->creator(pool);
-
-    /* Create buffer for comparison. */
-    str1.ptr = pj_pool_alloc(pool, BUFLEN);
-    str2.ptr = pj_pool_alloc(pool, BUFLEN);
-
-    /* Compare message type. */
-    if (parsed_msg->type != ref_msg->type) {
-	status = ERR_NOT_EQUAL;
-	goto on_return;
-    }
-
-    /* Compare request or status line. */
-    if (parsed_msg->type == PJSIP_REQUEST_MSG) {
-	pjsip_method *m1 = &parsed_msg->line.req.method;
-	pjsip_method *m2 = &ref_msg->line.req.method;
-
-	if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) {
-	    status = ERR_NOT_EQUAL;
-	    goto on_return;
-	}
-    } else {
-
-    }
-
-    /* Compare headers. */
-    hdr1 = parsed_msg->hdr.next;
-    hdr2 = ref_msg->hdr.next;
-
-    while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) {
-	len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN);
-	if (len < 1) {
-	    status = ERR_SYSTEM;
-	    goto on_return;
-	}
-	str1.slen = len;
-
-	len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN);
-	if (len < 1) {
-	    status = ERR_SYSTEM;
-	    goto on_return;
-	}
-	str2.slen = len;
-
-	if (!SILENT) {
-	    printf("hdr1='%.*s'\n"
-		   "hdr2='%.*s'\n\n",
-		   str1.slen, str1.ptr,
-		   str2.slen, str2.ptr);
-	}
-	if (pj_strcmp(&str1, &str2) != 0) {
-	    status = ERR_NOT_EQUAL;
-	    goto on_return;
-	}
-
-	hdr1 = hdr1->next;
-	hdr2 = hdr2->next;
-    }
-
-    if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) {
-	status = ERR_NOT_EQUAL;
-	goto on_return;
-    }
-
-    /* Print message. */
-#if IS_PROFILING
-print_msg:
-#endif
-    msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN);
-    if (msgbuf == NULL) {
-	status = ERR_SYSTEM;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t1);
-    len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN);
-    if (len < 1) {
-	status = ERR_SYSTEM;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    print_time += t2.u32.lo - t1.u32.lo;
-    status = PJ_SUCCESS;
-
-on_return:
-    pj_pool_release(pool);
-    return status;
-}
-
-static void warm_up()
-{
-    pj_pool_t *pool;
-    pool = pj_pool_create( pf, "", 
-			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 
-			   &pool_error);
-    pj_pool_release(pool);
-}
-
-
-pj_status_t test_msg(void)
-{
-    pj_status_t status;
-    unsigned i;
-
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-    warm_up();
-
-    for (i=0; i<LOOP; ++i) {
-	status = test_entry( &test_array[0] );
-    }
-    printf("%s\n", STATUS_STR(status));
-
-    printf("Total bytes: %u, parse time=%f/char, print time=%f/char\n", 
-	   parse_len, 
-	   parse_time*1.0/parse_len,
-	   print_time*1.0/parse_len);
-    return PJ_SUCCESS;
-}
-
-/*****************************************************************************/
-
-static pjsip_msg *create_msg0(pj_pool_t *pool)
-{
-
-    pjsip_msg *msg;
-    pjsip_name_addr *name_addr;
-    pjsip_url *url;
-    pjsip_fromto_hdr *fromto;
-    pjsip_cid_hdr *cid;
-    pjsip_clen_hdr *clen;
-    pjsip_cseq_hdr *cseq;
-    pjsip_contact_hdr *contact;
-    pjsip_ctype_hdr *ctype;
-    pjsip_routing_hdr *routing;
-    pjsip_via_hdr *via;
-    pjsip_generic_string_hdr *generic;
-    pj_str_t str;
-
-    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);
-
-    /* "INVITE sip:user@foo SIP/2.0\n" */
-    pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
-    url = pjsip_url_create(pool, 0);
-    msg->line.req.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "foo");
-
-    /* "From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r" */
-    fromto = pjsip_from_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
-    pj_strdup2(pool, &fromto->tag, "1234578901234567890");
-    name_addr = pjsip_name_addr_create(pool);
-    fromto->uri = (pjsip_uri*)name_addr;
-    pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "joe.user");
-    pj_strdup2(pool, &url->host, "bar.otherdomain.com");
-
-    /* "To: Fellow User <sip:user@foo.bar.domain.com>\r\n" */
-    fromto = pjsip_to_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
-    name_addr = pjsip_name_addr_create(pool);
-    fromto->uri = (pjsip_uri*)name_addr;
-    pj_strdup2(pool, &name_addr->display, "Fellow User");
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "foo.bar.domain.com");
-
-    /* "Call-ID: 12345678901234567890@bar\r\n" */
-    cid = pjsip_cid_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid);
-    pj_strdup2(pool, &cid->id, "12345678901234567890@bar");
-
-    /* "Content-Length: 0\r\n" */
-    clen = pjsip_clen_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen);
-    clen->len = 0;
-
-    /* "CSeq: 123456 INVITE\n" */
-    cseq = pjsip_cseq_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq);
-    cseq->cseq = 123456;
-    pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD);
-
-    /* "Contact: <sip:joe@bar>;q=0.5;expires=3600*/
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    contact->q1000 = 500;
-    contact->expires = 3600;
-    name_addr = pjsip_name_addr_create(pool);
-    contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "joe");
-    pj_strdup2(pool, &url->host, "bar");
-
-    /*, sip:user@host;q=0.500\r" */
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    contact->q1000 = 500;
-    url = pjsip_url_create(pool, 0);
-    contact->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "host");
-
-    /* "  ,sip:user2@host2\n" */
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    url = pjsip_url_create(pool, 0);
-    contact->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user2");
-    pj_strdup2(pool, &url->host, "host2");
-
-    /* "Content-Type: text/html; charset=ISO-8859-4\r" */
-    ctype = pjsip_ctype_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype);
-    pj_strdup2(pool, &ctype->media.type, "text");
-    pj_strdup2(pool, &ctype->media.subtype, "html");
-    pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4");
-
-    /* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
-    routing = pjsip_route_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
-    url->lr_param = 1;
-
-    /* "  <sip:server10.biloxi.com;lr>\r" */
-    routing = pjsip_route_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "server10.biloxi.com");
-    url->lr_param = 1;
-
-    /* "Record-Route: <sip:server10.biloxi.com>,\r\n" */
-    routing = pjsip_rr_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "server10.biloxi.com");
-    url->lr_param = 0;
-
-    /* "  <sip:bigbox3.site3.atlanta.com;lr>\n" */
-    routing = pjsip_rr_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
-    url->lr_param = 1;
-
-    /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "SCTP");
-    pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com");
-    pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1");
-
-    /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
-	" ;received=192.0.2.1\r\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "UDP");
-    pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com");
-    pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8");
-    pj_strdup2(pool, &via->recvd_param, "192.0.2.1");
-
-
-    /* "Via: SIP/2.0/UDP 10.2.1.1, */ 
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "UDP");
-    pj_strdup2(pool, &via->sent_by.host, "10.2.1.1");
-    
-    
-    /*SIP/2.0/TCP 192.168.1.1\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "TCP");
-    pj_strdup2(pool, &via->sent_by.host, "192.168.1.1");
-
-    /* "Organization: \r" */
-    str.ptr = "Organization";
-    str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    generic->hvalue.ptr = NULL;
-    generic->hvalue.slen = 0;
-
-    /* "Max-Forwards: 70\n" */
-    str.ptr = "Max-Forwards";
-    str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    str.ptr = "70";
-    str.slen = 2;
-    generic->hvalue = str;
-
-    /* "X-Header: \r\n" */
-    str.ptr = "X-Header";
-    str.slen = 8;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    str.ptr = NULL;
-    str.slen = 0;
-    generic->hvalue = str;
-
-    return msg;
-}
Index: pjproject/trunk/pjsip/src/test-pjsip/parse_uri.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/parse_uri.c	(revision 63)
+++ 	(revision )
@@ -1,660 +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/sip_parser.h>
-#include <pjsip/sip_uri.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "test.h"
-
-#define ERR_SYNTAX_ERR	(-2)
-#define ERR_NOT_EQUAL	(-3)
-
-#define ALPHANUM    "abcdefghijklmnopqrstuvwxyz" \
-		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
-		    "0123456789"
-#define MARK	    "-_.!~*'()"
-#define USER	    "&=+$,;?/%"
-#define PASS	    "&=+$,%"
-#define PARAM_CHAR  "[]/:&+$" MARK "%"
-
-#define POOL_SIZE	4096
-
-static const char *STATUS_STR(pj_status_t status)
-{
-    switch (status) {
-    case 0: return "OK";
-    case ERR_SYNTAX_ERR: return "Syntax Error";
-    case ERR_NOT_EQUAL: return "Not Equal";
-    }
-    return "???";
-}
-
-static pj_uint32_t parse_len, parse_time, print_time;
-static pj_caching_pool cp;
-
-
-/* URI creator functions. */
-static pjsip_uri *create_uri1( pj_pool_t *pool );
-static pjsip_uri *create_uri2( pj_pool_t *pool );
-static pjsip_uri *create_uri3( pj_pool_t *pool );
-static pjsip_uri *create_uri4( pj_pool_t *pool );
-static pjsip_uri *create_uri5( pj_pool_t *pool );
-static pjsip_uri *create_uri6( pj_pool_t *pool );
-static pjsip_uri *create_uri7( pj_pool_t *pool );
-static pjsip_uri *create_uri8( pj_pool_t *pool );
-static pjsip_uri *create_uri9( pj_pool_t *pool );
-static pjsip_uri *create_uri10( pj_pool_t *pool );
-static pjsip_uri *create_uri11( pj_pool_t *pool );
-static pjsip_uri *create_uri12( pj_pool_t *pool );
-static pjsip_uri *create_uri13( pj_pool_t *pool );
-static pjsip_uri *create_uri14( pj_pool_t *pool );
-static pjsip_uri *create_uri15( pj_pool_t *pool );
-static pjsip_uri *create_uri16( pj_pool_t *pool );
-static pjsip_uri *create_uri17( pj_pool_t *pool );
-static pjsip_uri *create_uri18( pj_pool_t *pool );
-static pjsip_uri *create_uri19( pj_pool_t *pool );
-static pjsip_uri *create_dummy( pj_pool_t *pool );
-
-struct uri_test
-{
-    pj_status_t	     status;
-    char	     str[PJSIP_MAX_URL_SIZE];
-    pjsip_uri *(*creator)(pj_pool_t *pool);
-    pj_size_t	     len;
-} uri_test_array[] = 
-{
-    {
-	PJ_SUCCESS,
-	"sip:localhost",
-	&create_uri1
-    },
-    {
-	PJ_SUCCESS,
-	"sip:user@localhost",
-	&create_uri2
-    },
-    {
-	PJ_SUCCESS,
-	"sip:user:password@localhost:5060",
-	&create_uri3,
-    },
-    {
-	/* Port is specified should not match unspecified port. */
-	ERR_NOT_EQUAL,
-	"sip:localhost:5060",
-	&create_uri4
-    },
-    {
-	/* All recognized parameters. */
-	PJ_SUCCESS,
-	"sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK",
-	&create_uri5
-    },
-    {
-	/* Params mixed with other params and header params. */
-	PJ_SUCCESS,
-	"sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
-	"?Subject=Hello%20There&Server=SIP%20Server",
-	&create_uri6
-    },
-    {
-	/* SIPS. */
-	PJ_SUCCESS,
-	"sips:localhost",
-	&create_uri7,
-    },
-    {
-	/* Name address */
-	PJ_SUCCESS,
-	"<sip:localhost>",
-	&create_uri8
-    },
-    {
-	/* Name address with display name and SIPS scheme with some redundant
-	 * whitespaced.
-	 */
-	PJ_SUCCESS,
-	"  Power Administrator  <sips:localhost>",
-	&create_uri9
-    },
-    {
-	/* Name address. */
-	PJ_SUCCESS,
-	" \"User\" <sip:user@localhost:5071>",
-	&create_uri10
-    },
-    {
-	/* Escaped sequence in display name (display=Strange User\"\\\"). */
-	PJ_SUCCESS,
-	" \"Strange User\\\"\\\\\\\"\" <sip:localhost>",
-	&create_uri11,
-    },
-    {
-	/* Errorneous escaping in display name. */
-	ERR_SYNTAX_ERR,
-	" \"Rogue User\\\" <sip:localhost>",
-	&create_uri12,
-    },
-    {
-	/* Dangling quote in display name, but that should be OK. */
-	PJ_SUCCESS,
-	"Strange User\" <sip:localhost>",
-	&create_uri13,
-    },
-    {
-	/* Special characters in parameter value must be quoted. */
-	PJ_SUCCESS,
-	"sip:localhost;pvalue=\"hello world\"",
-	&create_uri14,
-    },
-    {
-	/* Excercise strange character sets allowed in display, user, password,
-	 * host, and port. 
-	 */
-	PJ_SUCCESS,
-	"This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@"
-	"my_proxy09.MY-domain.com:9801>",
-	&create_uri15,
-    },
-    {
-	/* Another excercise to the allowed character sets to the hostname. */
-	PJ_SUCCESS,
-	"sip:" ALPHANUM "-_.com",
-	&create_uri16,
-    },
-    {
-	/* Another excercise to the allowed character sets to the username 
-	 * and password.
-	 */
-	PJ_SUCCESS,
-	"sip:" ALPHANUM USER ":" ALPHANUM PASS "@host",
-	&create_uri17,
-    },
-    {
-	/* Excercise to the pname and pvalue, and mixup of other-param
-	 * between 'recognized' params.
-	 */
-	PJ_SUCCESS,
-	"sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR 
-	";lr;other=1;transport=sctp;other2",
-	&create_uri18,
-    },
-    {
-	/* This should trigger syntax error. */
-	ERR_SYNTAX_ERR,
-	"sip:",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: whitespace after scheme. */
-	ERR_SYNTAX_ERR,
-	"sip :host",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: whitespace before hostname. */
-	ERR_SYNTAX_ERR,
-	"sip: host",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: invalid port. */
-	ERR_SYNTAX_ERR,
-	"sip:user:password",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: no host. */
-	ERR_SYNTAX_ERR,
-	"sip:user@",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: no user/host. */
-	ERR_SYNTAX_ERR,
-	"sip:@",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: empty string. */
-	ERR_SYNTAX_ERR,
-	"",
-	&create_dummy,
-    },
-    {
-	PJ_SUCCESS,
-	"",
-	NULL,
-    },
-};
-
-static pjsip_uri *create_uri1(pj_pool_t *pool)
-{
-    /* "sip:localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri2(pj_pool_t *pool)
-{
-    /* "sip:user@localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2( pool, &url->user, "user");
-    pj_strdup2( pool, &url->host, "localhost");
-
-    return (pjsip_uri*) url;
-}
-
-static pjsip_uri *create_uri3(pj_pool_t *pool)
-{
-    /* "sip:user:password@localhost:5060" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2( pool, &url->user, "user");
-    pj_strdup2( pool, &url->passwd, "password");
-    pj_strdup2( pool, &url->host, "localhost");
-    url->port = 5060;
-
-    return (pjsip_uri*) url;
-}
-
-static pjsip_uri *create_uri4(pj_pool_t *pool)
-{
-    /* Like: "sip:localhost:5060", but without the port. */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri5(pj_pool_t *pool)
-{
-    /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->transport_param, "tcp");
-    pj_strdup2(pool, &url->user_param, "ip");
-    url->ttl_param = 255;
-    url->lr_param = 1;
-    pj_strdup2(pool, &url->maddr_param, "127.0.0.1");
-    pj_strdup2(pool, &url->method_param, "ACK");
-
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri6(pj_pool_t *pool)
-{
-    /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
-       "?Subject=Hello%20There&Server=SIP%20Server" 
-     */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->user_param, "phone");
-    pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry");
-    pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server");
-    return (pjsip_uri*)url;
-
-}
-
-static pjsip_uri *create_uri7(pj_pool_t *pool)
-{
-    /* "sips:localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 1);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri8(pj_pool_t *pool)
-{
-    /* "<sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri9(pj_pool_t *pool)
-{
-    /* "  Power Administrator <sips:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 1);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "Power Administrator");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri10(pj_pool_t *pool)
-{
-    /* " \"User\" <sip:user@localhost:5071>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"User\"");
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "localhost");
-    url->port = 5071;
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri11(pj_pool_t *pool)
-{
-    /* " \"Strange User\\\"\\\\\\\"\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri12(pj_pool_t *pool)
-{
-    /* " \"Rogue User\\\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri13(pj_pool_t *pool)
-{
-    /* "Strange User\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "Strange User\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri14(pj_pool_t *pool)
-{
-    /* "sip:localhost;pvalue=\"hello world\"" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri15(pj_pool_t *pool)
-{
-    /* "This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@my_proxy09.my-domain.com:9801>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");
-    pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c");
-    pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,");
-    pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com");
-    url->port = 9801;
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri16(pj_pool_t *pool)
-{
-    /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri17(pj_pool_t *pool)
-{
-    /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->user, ALPHANUM USER);
-    pj_strdup2(pool, &url->passwd, ALPHANUM PASS);
-    pj_strdup2(pool, &url->host, "host");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri18(pj_pool_t *pool)
-{
-    /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, "host");
-    pj_strdup2(pool, &url->user_param, "ip");
-    pj_strdup2(pool, &url->transport_param, "sctp");
-    pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2");    
-    url->lr_param = 1;
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_dummy(pj_pool_t *pool)
-{
-    PJ_UNUSED_ARG(pool)
-    return NULL;
-}
-
-/*****************************************************************************/
-
-static void pool_error(pj_pool_t *pool, pj_size_t sz)
-{
-    PJ_UNUSED_ARG(pool)
-    PJ_UNUSED_ARG(sz)
-
-    pj_assert(0);
-    exit(1);
-}
-
-/*
- * Test one test entry.
- */
-static pj_status_t test_entry(struct uri_test *entry)
-{
-    pj_status_t status;
-    pj_pool_t *pool;
-    int len;
-    pjsip_uri *parsed_uri, *ref_uri;
-    pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0};
-    pj_hr_timestamp t1, t2;
-
-    pool = (*cp.factory.create_pool)( &cp.factory, "", POOL_SIZE, 0, &pool_error);
-
-    /* Parse URI text. */
-    pj_hr_gettimestamp(&t1);
-    parse_len += entry->len;
-    parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0);
-    if (!parsed_uri) {
-	/* Parsing failed. If the entry says that this is expected, then
-	 * return OK.
-	 */
-	status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : ERR_SYNTAX_ERR;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    parse_time += t2.u32.lo - t1.u32.lo;
-
-    /* Create the reference URI. */
-    ref_uri = entry->creator(pool);
-
-    /* Print both URI. */
-    s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-    s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-
-    pj_hr_gettimestamp(&t1);
-    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE);
-    if (len < 1) {
-	status = -1;
-	goto on_return;
-    }
-    s1.slen = len;
-
-    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE);
-    if (len < 1) {
-	status = -1;
-	goto on_return;
-    }
-    s2.slen = len;
-    pj_hr_gettimestamp(&t2);
-    print_time += t2.u32.lo - t1.u32.lo;
-
-    /* Full comparison of parsed URI with reference URI. */
-    if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) {
-	/* Not equal. See if this is the expected status. */
-	status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : ERR_NOT_EQUAL;
-	goto on_return;
-
-    } else {
-	/* Equal. See if this is the expected status. */
-	status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -1;
-	if (status != PJ_SUCCESS) {
-	    goto on_return;
-	}
-    }
-
-    /* Compare text. */
-    if (pj_strcmp(&s1, &s2) != 0) {
-	/* Not equal. */
-	status = ERR_NOT_EQUAL;
-    }
-
-on_return:
-    if (!SILENT) {
-	printf("%.2d %s (expected status=%s)\n"
-	       "   str=%s\n"
-	       "   uri=%.*s\n"
-	       "   ref=%.*s\n\n", 
-	       entry-uri_test_array, 
-	       STATUS_STR(status), 
-	       STATUS_STR(entry->status), 
-	       entry->str, 
-	       (int)s1.slen, s1.ptr, (int)s2.slen, s2.ptr);
-    }
-
-    pj_pool_release(pool);
-    return status;
-}
-
-static void warm_up(pj_pool_factory *pf)
-{
-    pj_pool_t *pool;
-    struct uri_test *entry;
-
-    pool = pj_pool_create(pf, "", POOL_SIZE, 0, &pool_error);
-    pjsip_parse_uri(pool, "sip:host", 8, 0);
-    entry = &uri_test_array[0];
-    while (entry->creator) {
-	entry->len = strlen(entry->str);
-	++entry;
-    }
-    pj_pool_release(pool);
-}
-
-//#if !IS_PROFILING
-#if 1
-pj_status_t test_uri()
-{
-    struct uri_test *entry;
-    int i=0, err=0;
-    pj_status_t status;
-    pj_hr_timestamp t1, t2;
-    pj_uint32_t total_time;
-
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-    warm_up(&cp.factory);
-
-    pj_hr_gettimestamp(&t1);
-    for (i=0; i<LOOP; ++i) {
-	entry = &uri_test_array[0];
-	while (entry->creator) {
-	    status = test_entry(entry);
-	    if (status != PJ_SUCCESS) {
-		++err;
-	    }
-	    ++entry;
-	}
-    }
-    pj_hr_gettimestamp(&t2);
-    total_time = t2.u32.lo - t1.u32.lo;
-
-    printf("Error=%d\n", err);
-    printf("Total parse len:  %u bytes\n", parse_len);
-    printf("Total parse time: %u (%f/char), print time: %u (%f/char)\n", 
-	    parse_time, parse_time*1.0/parse_len,
-	    print_time, print_time*1.0/parse_len);
-    printf("Total time: %u (%f/char)\n", total_time, total_time*1.0/parse_len);
-    return err;
-}
-
-#else
-
-pj_status_t test_uri()
-{
-    struct uri_test *entry;
-    unsigned i;
-
-    warm_up();
-    pj_caching_pool_init(&cp, 1024*1024);
-
-    for (i=0; i<LOOP; ++i) {
-	entry = &uri_test_array[0];
-	while (entry->creator) {
-	    pj_pool_t *pool;
-	    pjsip_uri *uri1, *uri2;
-
-	    pool = pj_pool_create( &cp.factory, "", POOL_SIZE, 0, &pool_error);
-	    uri1 = pjsip_parse_uri(pool, entry->str, strlen(entry->str));
-	    pj_pool_release(pool);
-	    ++entry;
-	}
-    }
-
-    return 0;
-}
-
-#endif
Index: pjproject/trunk/pjsip/src/test-pjsip/test.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/test.c	(revision 63)
+++ pjproject/trunk/pjsip/src/test-pjsip/test.c	(revision 64)
@@ -47,18 +47,57 @@
 }
 
+pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules)
+{
+    *count = 0;
+    return PJ_SUCCESS;
+}
 
-
-int main()
+int test_main(void)
 {
     pj_status_t rc;
+    pj_caching_pool caching_pool;
+    const char *filename;
+    int line;
+
+    pj_log_set_level(3);
+    pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | 
+                     PJ_LOG_HAS_MICRO_SEC);
 
     if ((rc=pj_init()) != PJ_SUCCESS) {
 	app_perror("pj_init", rc);
+	return rc;
     }
 
-    DO_TEST(parse_uri());
-    DO_TEST(parse_msg());
+    pj_dump_config();
+
+    pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
+
+    rc = pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt);
+    if (rc != PJ_SUCCESS) {
+	app_perror("pjsip_endpt_create", rc);
+	pj_caching_pool_destroy(&caching_pool);
+	return rc;
+    }
+
+    PJ_LOG(3,("",""));
+
+    DO_TEST(uri_test());
 
 on_return:
+
+    pjsip_endpt_destroy(endpt);
+    pj_caching_pool_destroy(&caching_pool);
+
+    PJ_LOG(3,("test", ""));
+ 
+    pj_thread_get_stack_info(pj_thread_this(), &filename, &line);
+    PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", 
+	              pj_thread_get_stack_max_usage(pj_thread_this()),
+		      filename, line));
+    if (rc == 0)
+	PJ_LOG(3,("test", "Looks like everything is okay!.."));
+    else
+	PJ_LOG(3,("test", "Test completed with error(s)"));
+
     return 0;
 }
Index: pjproject/trunk/pjsip/src/test-pjsip/test.h
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/test.h	(revision 63)
+++ pjproject/trunk/pjsip/src/test-pjsip/test.h	(revision 64)
@@ -22,13 +22,10 @@
 #include <pjsip/sip_types.h>
 
-#define SILENT		1
-#define IS_PROFILING	1
-#define LOOP		2000
-
 extern pjsip_endpoint *endpt;
 
-pj_status_t parse_uri(void);
-pj_status_t parse_msg(void);
+pj_status_t uri_test(void);
+pj_status_t msg_test(void);
 
+int  test_main(void);
 void app_perror(const char *msg, pj_status_t status);
 
Index: pjproject/trunk/pjsip/src/test-pjsip/uri.c
===================================================================
--- pjproject/trunk/pjsip/src/test-pjsip/uri.c	(revision 64)
+++ pjproject/trunk/pjsip/src/test-pjsip/uri.c	(revision 64)
@@ -0,0 +1,560 @@
+/* $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_core.h>
+#include <pjlib.h>
+
+
+#define ALPHANUM    "abcdefghijklmnopqrstuvwxyz" \
+		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+		    "0123456789"
+#define MARK	    "-_.!~*'()"
+#define USER	    "&=+$,;?/%"
+#define PASS	    "&=+$,%"
+#define PARAM_CHAR  "[]/:&+$" MARK "%"
+
+#define POOL_SIZE	4096
+
+static pj_uint32_t parse_len, parse_time, print_time;
+
+
+/* URI creator functions. */
+static pjsip_uri *create_uri1( pj_pool_t *pool );
+static pjsip_uri *create_uri2( pj_pool_t *pool );
+static pjsip_uri *create_uri3( pj_pool_t *pool );
+static pjsip_uri *create_uri4( pj_pool_t *pool );
+static pjsip_uri *create_uri5( pj_pool_t *pool );
+static pjsip_uri *create_uri6( pj_pool_t *pool );
+static pjsip_uri *create_uri7( pj_pool_t *pool );
+static pjsip_uri *create_uri8( pj_pool_t *pool );
+static pjsip_uri *create_uri9( pj_pool_t *pool );
+static pjsip_uri *create_uri10( pj_pool_t *pool );
+static pjsip_uri *create_uri11( pj_pool_t *pool );
+static pjsip_uri *create_uri12( pj_pool_t *pool );
+static pjsip_uri *create_uri13( pj_pool_t *pool );
+static pjsip_uri *create_uri14( pj_pool_t *pool );
+static pjsip_uri *create_uri15( pj_pool_t *pool );
+static pjsip_uri *create_uri16( pj_pool_t *pool );
+static pjsip_uri *create_uri17( pj_pool_t *pool );
+static pjsip_uri *create_uri18( pj_pool_t *pool );
+static pjsip_uri *create_uri19( pj_pool_t *pool );
+static pjsip_uri *create_dummy( pj_pool_t *pool );
+
+#define ERR_NOT_EQUAL	-1001
+#define ERR_SYNTAX_ERR	-1002
+
+struct uri_test
+{
+    pj_status_t	     status;
+    char	     str[PJSIP_MAX_URL_SIZE];
+    pjsip_uri *(*creator)(pj_pool_t *pool);
+    pj_size_t	     len;
+} uri_test_array[] = 
+{
+    {
+	PJ_SUCCESS,
+	"sip:localhost",
+	&create_uri1
+    },
+    {
+	PJ_SUCCESS,
+	"sip:user@localhost",
+	&create_uri2
+    },
+    {
+	PJ_SUCCESS,
+	"sip:user:password@localhost:5060",
+	&create_uri3,
+    },
+    {
+	/* Port is specified should not match unspecified port. */
+	ERR_NOT_EQUAL,
+	"sip:localhost:5060",
+	&create_uri4
+    },
+    {
+	/* All recognized parameters. */
+	PJ_SUCCESS,
+	"sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK",
+	&create_uri5
+    },
+    {
+	/* Params mixed with other params and header params. */
+	PJ_SUCCESS,
+	"sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
+	"?Subject=Hello%20There&Server=SIP%20Server",
+	&create_uri6
+    },
+    {
+	/* SIPS. */
+	PJ_SUCCESS,
+	"sips:localhost",
+	&create_uri7,
+    },
+    {
+	/* Name address */
+	PJ_SUCCESS,
+	"<sip:localhost>",
+	&create_uri8
+    },
+    {
+	/* Name address with display name and SIPS scheme with some redundant
+	 * whitespaced.
+	 */
+	PJ_SUCCESS,
+	"  Power Administrator  <sips:localhost>",
+	&create_uri9
+    },
+    {
+	/* Name address. */
+	PJ_SUCCESS,
+	" \"User\" <sip:user@localhost:5071>",
+	&create_uri10
+    },
+    {
+	/* Escaped sequence in display name (display=Strange User\"\\\"). */
+	PJ_SUCCESS,
+	" \"Strange User\\\"\\\\\\\"\" <sip:localhost>",
+	&create_uri11,
+    },
+    {
+	/* Errorneous escaping in display name. */
+	ERR_SYNTAX_ERR,
+	" \"Rogue User\\\" <sip:localhost>",
+	&create_uri12,
+    },
+    {
+	/* Dangling quote in display name, but that should be OK. */
+	PJ_SUCCESS,
+	"Strange User\" <sip:localhost>",
+	&create_uri13,
+    },
+    {
+	/* Special characters in parameter value must be quoted. */
+	PJ_SUCCESS,
+	"sip:localhost;pvalue=\"hello world\"",
+	&create_uri14,
+    },
+    {
+	/* Excercise strange character sets allowed in display, user, password,
+	 * host, and port. 
+	 */
+	PJ_SUCCESS,
+	"This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@"
+	"my_proxy09.MY-domain.com:9801>",
+	&create_uri15,
+    },
+    {
+	/* Another excercise to the allowed character sets to the hostname. */
+	PJ_SUCCESS,
+	"sip:" ALPHANUM "-_.com",
+	&create_uri16,
+    },
+    {
+	/* Another excercise to the allowed character sets to the username 
+	 * and password.
+	 */
+	PJ_SUCCESS,
+	"sip:" ALPHANUM USER ":" ALPHANUM PASS "@host",
+	&create_uri17,
+    },
+    {
+	/* Excercise to the pname and pvalue, and mixup of other-param
+	 * between 'recognized' params.
+	 */
+	PJ_SUCCESS,
+	"sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR 
+	";lr;other=1;transport=sctp;other2",
+	&create_uri18,
+    },
+    {
+	/* This should trigger syntax error. */
+	ERR_SYNTAX_ERR,
+	"sip:",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: whitespace after scheme. */
+	ERR_SYNTAX_ERR,
+	"sip :host",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: whitespace before hostname. */
+	ERR_SYNTAX_ERR,
+	"sip: host",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: invalid port. */
+	ERR_SYNTAX_ERR,
+	"sip:user:password",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: no host. */
+	ERR_SYNTAX_ERR,
+	"sip:user@",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: no user/host. */
+	ERR_SYNTAX_ERR,
+	"sip:@",
+	&create_dummy,
+    },
+    {
+	/* Syntax error: empty string. */
+	ERR_SYNTAX_ERR,
+	"",
+	&create_dummy,
+    }
+};
+
+static pjsip_uri *create_uri1(pj_pool_t *pool)
+{
+    /* "sip:localhost" */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri2(pj_pool_t *pool)
+{
+    /* "sip:user@localhost" */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2( pool, &url->user, "user");
+    pj_strdup2( pool, &url->host, "localhost");
+
+    return (pjsip_uri*) url;
+}
+
+static pjsip_uri *create_uri3(pj_pool_t *pool)
+{
+    /* "sip:user:password@localhost:5060" */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2( pool, &url->user, "user");
+    pj_strdup2( pool, &url->passwd, "password");
+    pj_strdup2( pool, &url->host, "localhost");
+    url->port = 5060;
+
+    return (pjsip_uri*) url;
+}
+
+static pjsip_uri *create_uri4(pj_pool_t *pool)
+{
+    /* Like: "sip:localhost:5060", but without the port. */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri5(pj_pool_t *pool)
+{
+    /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2(pool, &url->host, "localhost");
+    pj_strdup2(pool, &url->transport_param, "tcp");
+    pj_strdup2(pool, &url->user_param, "ip");
+    url->ttl_param = 255;
+    url->lr_param = 1;
+    pj_strdup2(pool, &url->maddr_param, "127.0.0.1");
+    pj_strdup2(pool, &url->method_param, "ACK");
+
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri6(pj_pool_t *pool)
+{
+    /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
+       "?Subject=Hello%20There&Server=SIP%20Server" 
+     */
+    pjsip_url *url = pjsip_url_create(pool, 0);
+
+    pj_strdup2(pool, &url->host, "localhost");
+    pj_strdup2(pool, &url->user_param, "phone");
+    pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry");
+    pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server");
+    return (pjsip_uri*)url;
+
+}
+
+static pjsip_uri *create_uri7(pj_pool_t *pool)
+{
+    /* "sips:localhost" */
+    pjsip_url *url = pjsip_url_create(pool, 1);
+
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri8(pj_pool_t *pool)
+{
+    /* "<sip:localhost>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri9(pj_pool_t *pool)
+{
+    /* "  Power Administrator <sips:localhost>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 1);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "Power Administrator");
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri10(pj_pool_t *pool)
+{
+    /* " \"User\" <sip:user@localhost:5071>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "\"User\"");
+    pj_strdup2(pool, &url->user, "user");
+    pj_strdup2(pool, &url->host, "localhost");
+    url->port = 5071;
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri11(pj_pool_t *pool)
+{
+    /* " \"Strange User\\\"\\\\\\\"\" <sip:localhost>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\"");
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri12(pj_pool_t *pool)
+{
+    /* " \"Rogue User\\\" <sip:localhost>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\"");
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri13(pj_pool_t *pool)
+{
+    /* "Strange User\" <sip:localhost>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "Strange User\"");
+    pj_strdup2(pool, &url->host, "localhost");
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri14(pj_pool_t *pool)
+{
+    /* "sip:localhost;pvalue=\"hello world\"" */
+    pjsip_url *url;
+    url = pjsip_url_create(pool, 0);
+    pj_strdup2(pool, &url->host, "localhost");
+    pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri15(pj_pool_t *pool)
+{
+    /* "This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@my_proxy09.my-domain.com:9801>" */
+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+    pjsip_url *url;
+
+    url = pjsip_url_create(pool, 0);
+    name_addr->uri = (pjsip_uri*) url;
+
+    pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");
+    pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c");
+    pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,");
+    pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com");
+    url->port = 9801;
+    return (pjsip_uri*)name_addr;
+}
+
+static pjsip_uri *create_uri16(pj_pool_t *pool)
+{
+    /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
+    pjsip_url *url;
+    url = pjsip_url_create(pool, 0);
+    pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri17(pj_pool_t *pool)
+{
+    /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */
+    pjsip_url *url;
+    url = pjsip_url_create(pool, 0);
+    pj_strdup2(pool, &url->user, ALPHANUM USER);
+    pj_strdup2(pool, &url->passwd, ALPHANUM PASS);
+    pj_strdup2(pool, &url->host, "host");
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_uri18(pj_pool_t *pool)
+{
+    /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */
+    pjsip_url *url;
+    url = pjsip_url_create(pool, 0);
+    pj_strdup2(pool, &url->host, "host");
+    pj_strdup2(pool, &url->user_param, "ip");
+    pj_strdup2(pool, &url->transport_param, "sctp");
+    pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2");    
+    url->lr_param = 1;
+    return (pjsip_uri*)url;
+}
+
+static pjsip_uri *create_dummy(pj_pool_t *pool)
+{
+    PJ_UNUSED_ARG(pool);
+    return NULL;
+}
+
+/*****************************************************************************/
+
+/*
+ * Test one test entry.
+ */
+static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry)
+{
+    pj_status_t status;
+    int len;
+    pjsip_uri *parsed_uri, *ref_uri;
+    pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0};
+    pj_timestamp t1, t2;
+
+    entry->len = pj_native_strlen(entry->str);
+
+    /* Parse URI text. */
+    pj_get_timestamp(&t1);
+    parse_len += entry->len;
+    parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0);
+    if (!parsed_uri) {
+	/* Parsing failed. If the entry says that this is expected, then
+	 * return OK.
+	 */
+	status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : -10;
+	goto on_return;
+    }
+    pj_get_timestamp(&t2);
+    parse_time += t2.u32.lo - t1.u32.lo;
+
+    /* Create the reference URI. */
+    ref_uri = entry->creator(pool);
+
+    /* Print both URI. */
+    s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+    s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+
+    pj_get_timestamp(&t1);
+    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE);
+    if (len < 1) {
+	status = -20;
+	goto on_return;
+    }
+    s1.slen = len;
+
+    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE);
+    if (len < 1) {
+	status = -30;
+	goto on_return;
+    }
+    s2.slen = len;
+    pj_get_timestamp(&t2);
+    print_time += t2.u32.lo - t1.u32.lo;
+
+    /* Full comparison of parsed URI with reference URI. */
+    if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) {
+	/* Not equal. See if this is the expected status. */
+	status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : -40;
+	goto on_return;
+
+    } else {
+	/* Equal. See if this is the expected status. */
+	status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -50;
+	if (status != PJ_SUCCESS) {
+	    goto on_return;
+	}
+    }
+
+    /* Compare text. */
+    if (pj_strcmp(&s1, &s2) != 0) {
+	/* Not equal. */
+	status = -60;
+    }
+
+on_return:
+    return status;
+}
+
+pj_status_t uri_test()
+{
+    unsigned i;
+    pj_pool_t *pool;
+    pj_status_t status;
+
+    pool = pjsip_endpt_create_pool(endpt, "", 4000, 4000);
+
+    for (i=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) {
+	status = do_uri_test(pool, &uri_test_array[i]);
+	if (status != PJ_SUCCESS) {
+	    PJ_LOG(3,("uri_test", "  error %d when testing entry %d",
+		      status, i));
+	    break;
+	}
+    }
+
+    pjsip_endpt_destroy_pool(endpt, pool);
+    return status;
+}
+
