Set svn:eol-style property

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@65 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib-util/src/pjlib-util-test/main.c b/pjlib-util/src/pjlib-util-test/main.c
index 2fc23a7..9925b71 100644
--- a/pjlib-util/src/pjlib-util-test/main.c
+++ b/pjlib-util/src/pjlib-util-test/main.c
@@ -1,53 +1,53 @@
-/* $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"

-

-#if defined(PJ_SUNOS) && PJ_SUNOS!=0

-#include <signal.h>

-static void init_signals()

-{

-    struct sigaction act;

-

-    memset(&act, 0, sizeof(act));

-    act.sa_handler = SIG_IGN;

-

-    sigaction(SIGALRM, &act, NULL);

-}

-

-#else

-#define init_signals()

-#endif

-

-#define boost()

-

-int main(int argc, char *argv[])

-{

-    int rc;

-

-    PJ_UNUSED_ARG(argc);

-    PJ_UNUSED_ARG(argv);

-

-    boost();

-    init_signals();

-

-    rc = test_main();

-

-    return rc;

-}

-

+/* $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"
+
+#if defined(PJ_SUNOS) && PJ_SUNOS!=0
+#include <signal.h>
+static void init_signals()
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = SIG_IGN;
+
+    sigaction(SIGALRM, &act, NULL);
+}
+
+#else
+#define init_signals()
+#endif
+
+#define boost()
+
+int main(int argc, char *argv[])
+{
+    int rc;
+
+    PJ_UNUSED_ARG(argc);
+    PJ_UNUSED_ARG(argv);
+
+    boost();
+    init_signals();
+
+    rc = test_main();
+
+    return rc;
+}
+
diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c
index 511e7a1..991c1c3 100644
--- a/pjlib-util/src/pjlib-util-test/test.c
+++ b/pjlib-util/src/pjlib-util-test/test.c
@@ -1,86 +1,86 @@
-/* $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 <pjlib.h>

-

-void app_perror(const char *msg, pj_status_t rc)

-{

-    char errbuf[256];

-

-    PJ_CHECK_STACK();

-

-    pj_strerror(rc, errbuf, sizeof(errbuf));

-    PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));

-}

-

-#define DO_TEST(test)	do { \

-			    PJ_LOG(3, ("test", "Running %s...", #test));  \

-			    rc = test; \

-			    PJ_LOG(3, ("test",  \

-				       "%s(%d)",  \

-				       (char*)(rc ? "..ERROR" : "..success"), rc)); \

-			    if (rc!=0) goto on_return; \

-			} while (0)

-

-

-pj_pool_factory *mem;

-

-

-static int test_inner(void)

-{

-    pj_caching_pool caching_pool;

-    int rc = 0;

-

-    mem = &caching_pool.factory;

-

-    pj_log_set_level(3);

-    pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | 

-                     PJ_LOG_HAS_MICRO_SEC);

-

-    rc = pj_init();

-    if (rc != 0) {

-	app_perror("pj_init() error!!", rc);

-	return rc;

-    }

-    

-    pj_dump_config();

-    pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );

-    DO_TEST(xml_test());

-

-on_return:

-    return rc;

-}

-

-int test_main(void)

-{

-    PJ_USE_EXCEPTION;

-

-    PJ_TRY {

-        return test_inner();

-    }

-    PJ_DEFAULT {

-        int id = PJ_GET_EXCEPTION();

-        PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", 

-                  id, pj_exception_id_name(id)));

-    }

-    PJ_END;

-

-    return -1;

-}

-

+/* $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 <pjlib.h>
+
+void app_perror(const char *msg, pj_status_t rc)
+{
+    char errbuf[256];
+
+    PJ_CHECK_STACK();
+
+    pj_strerror(rc, errbuf, sizeof(errbuf));
+    PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
+}
+
+#define DO_TEST(test)	do { \
+			    PJ_LOG(3, ("test", "Running %s...", #test));  \
+			    rc = test; \
+			    PJ_LOG(3, ("test",  \
+				       "%s(%d)",  \
+				       (char*)(rc ? "..ERROR" : "..success"), rc)); \
+			    if (rc!=0) goto on_return; \
+			} while (0)
+
+
+pj_pool_factory *mem;
+
+
+static int test_inner(void)
+{
+    pj_caching_pool caching_pool;
+    int rc = 0;
+
+    mem = &caching_pool.factory;
+
+    pj_log_set_level(3);
+    pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | 
+                     PJ_LOG_HAS_MICRO_SEC);
+
+    rc = pj_init();
+    if (rc != 0) {
+	app_perror("pj_init() error!!", rc);
+	return rc;
+    }
+    
+    pj_dump_config();
+    pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
+    DO_TEST(xml_test());
+
+on_return:
+    return rc;
+}
+
+int test_main(void)
+{
+    PJ_USE_EXCEPTION;
+
+    PJ_TRY {
+        return test_inner();
+    }
+    PJ_DEFAULT {
+        int id = PJ_GET_EXCEPTION();
+        PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", 
+                  id, pj_exception_id_name(id)));
+    }
+    PJ_END;
+
+    return -1;
+}
+
diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h
index c446729..c3ef3e4 100644
--- a/pjlib-util/src/pjlib-util-test/test.h
+++ b/pjlib-util/src/pjlib-util-test/test.h
@@ -1,28 +1,28 @@
-/* $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 <pj/types.h>

-

-#define INCLUDE_XML_TEST	1

-

-extern int xml_test(void);

-extern int test_main(void);

-

-extern void app_perror(const char *title, pj_status_t rc);

-extern pj_pool_factory *mem;

-

+/* $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 <pj/types.h>
+
+#define INCLUDE_XML_TEST	1
+
+extern int xml_test(void);
+extern int test_main(void);
+
+extern void app_perror(const char *title, pj_status_t rc);
+extern pj_pool_factory *mem;
+
diff --git a/pjlib-util/src/pjlib-util-test/xml.c b/pjlib-util/src/pjlib-util-test/xml.c
index 9ad4a73..e20a68f 100644
--- a/pjlib-util/src/pjlib-util-test/xml.c
+++ b/pjlib-util/src/pjlib-util-test/xml.c
@@ -1,145 +1,145 @@
-/* $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"

-

-

-#if INCLUDE_XML_TEST

-

-#include <pjlib-util/xml.h>

-#include <pjlib.h>

-

-#define THIS_FILE   "xml_test"

-

-static const char *xml_doc[] =

-{

-"   <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

-"   <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"

-"          xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n"

-"          xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n"

-"          xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n"

-"          entity=\"pres:someone@example.com\"\n"

-"          version=\"567\">\n"

-"\n"

-"    <tuple id=\"sg89ae\">\n"

-"     <status>\n"

-"      <basic>open</basic>\n"

-"      <r:relationship>assistant</r:relationship>\n"

-"     </status>\n"

-"     <c:servcaps>\n"

-"      <c:audio>true</c:audio>\n"

-"      <c:video>false</c:video>\n"

-"      <c:message>true</c:message>\n"

-"     </c:servcaps>\n"

-"     <contact priority=\"0.8\">tel:09012345678</contact>\n"

-"    </tuple>\n"

-"\n"

-"    <tuple id=\"cg231jcr\">\n"

-"     <status>\n"

-"      <basic>open</basic>\n"

-"     </status>\n"

-"     <contact priority=\"1.0\">im:pep@example.com</contact>\n"

-"    </tuple>\n"

-"\n"

-"    <tuple id=\"r1230d\">\n"

-"     <status>\n"

-"      <basic>closed</basic>\n"

-"      <r:activity>meeting</r:activity>\n"

-"     </status>\n"

-"     <r:homepage>http://example.com/~pep/</r:homepage>\n"

-"     <r:icon>http://example.com/~pep/icon.gif</r:icon>\n"

-"     <r:card>http://example.com/~pep/card.vcd</r:card>\n"

-"     <contact priority=\"0.9\">sip:pep@example.com</contact>\n"

-"    </tuple>\n"

-"\n"

-"    <note xml:lang=\"en\">Full state presence document</note>\n"

-"\n"

-"    <r:person>\n"

-"     <r:status>\n"

-"      <r:activities>\n"

-"       <r:on-the-phone/>\n"

-"       <r:busy/>\n"

-"      </r:activities>\n"

-"     </r:status>\n"

-"    </r:person>\n"

-"\n"

-"    <r:device id=\"urn:esn:600b40c7\">\n"

-"     <r:status>\n"

-"      <c:devcaps>\n"

-"       <c:mobility>\n"

-"        <c:supported>\n"

-"         <c:mobile/>\n"

-"        </c:supported>\n"

-"       </c:mobility>\n"

-"      </c:devcaps>\n"

-"     </r:status>\n"

-"    </r:device>\n"

-"\n"

-"   </p:pidf-full>\n"

-}

-;

-

-static int xml_parse_print_test(const char *doc)

-{

-    pj_str_t msg;

-    pj_pool_t *pool;

-    pj_xml_node *root;

-    char *output;

-    int output_len;

-

-    pool = pj_pool_create(mem, "xml", 4096, 1024, NULL);

-    pj_strdup2(pool, &msg, doc);

-    root = pj_xml_parse(pool, msg.ptr, msg.slen);

-    if (!root) {

-	PJ_LOG(1, (THIS_FILE, "  Error: unable to parse XML"));

-	return -10;

-    }

-

-    output = (char*)pj_pool_alloc(pool, msg.slen + 512);

-    pj_memset(output, 0, msg.slen+512);

-    output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE);

-    if (output_len < 1) {

-	PJ_LOG(1, (THIS_FILE, "  Error: buffer too small to print XML file"));

-	return -20;

-    }

-    output[output_len] = '\0';

-

-

-    pj_pool_release(pool);

-    return 0;

-}

-

-int xml_test()

-{

-    unsigned i;

-    for (i=0; i<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) {

-	int status;

-	if ((status=xml_parse_print_test(xml_doc[i])) != 0)

-	    return status;

-    }

-    return 0;

-}

-

-#else

-/* To prevent warning about "translation unit is empty"

- * when this test is disabled. 

- */

-int dummy_xml_test;

-#endif	/* INCLUDE_XML_TEST */

-

-

+/* $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"
+
+
+#if INCLUDE_XML_TEST
+
+#include <pjlib-util/xml.h>
+#include <pjlib.h>
+
+#define THIS_FILE   "xml_test"
+
+static const char *xml_doc[] =
+{
+"   <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"   <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"
+"          xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n"
+"          xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n"
+"          xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n"
+"          entity=\"pres:someone@example.com\"\n"
+"          version=\"567\">\n"
+"\n"
+"    <tuple id=\"sg89ae\">\n"
+"     <status>\n"
+"      <basic>open</basic>\n"
+"      <r:relationship>assistant</r:relationship>\n"
+"     </status>\n"
+"     <c:servcaps>\n"
+"      <c:audio>true</c:audio>\n"
+"      <c:video>false</c:video>\n"
+"      <c:message>true</c:message>\n"
+"     </c:servcaps>\n"
+"     <contact priority=\"0.8\">tel:09012345678</contact>\n"
+"    </tuple>\n"
+"\n"
+"    <tuple id=\"cg231jcr\">\n"
+"     <status>\n"
+"      <basic>open</basic>\n"
+"     </status>\n"
+"     <contact priority=\"1.0\">im:pep@example.com</contact>\n"
+"    </tuple>\n"
+"\n"
+"    <tuple id=\"r1230d\">\n"
+"     <status>\n"
+"      <basic>closed</basic>\n"
+"      <r:activity>meeting</r:activity>\n"
+"     </status>\n"
+"     <r:homepage>http://example.com/~pep/</r:homepage>\n"
+"     <r:icon>http://example.com/~pep/icon.gif</r:icon>\n"
+"     <r:card>http://example.com/~pep/card.vcd</r:card>\n"
+"     <contact priority=\"0.9\">sip:pep@example.com</contact>\n"
+"    </tuple>\n"
+"\n"
+"    <note xml:lang=\"en\">Full state presence document</note>\n"
+"\n"
+"    <r:person>\n"
+"     <r:status>\n"
+"      <r:activities>\n"
+"       <r:on-the-phone/>\n"
+"       <r:busy/>\n"
+"      </r:activities>\n"
+"     </r:status>\n"
+"    </r:person>\n"
+"\n"
+"    <r:device id=\"urn:esn:600b40c7\">\n"
+"     <r:status>\n"
+"      <c:devcaps>\n"
+"       <c:mobility>\n"
+"        <c:supported>\n"
+"         <c:mobile/>\n"
+"        </c:supported>\n"
+"       </c:mobility>\n"
+"      </c:devcaps>\n"
+"     </r:status>\n"
+"    </r:device>\n"
+"\n"
+"   </p:pidf-full>\n"
+}
+;
+
+static int xml_parse_print_test(const char *doc)
+{
+    pj_str_t msg;
+    pj_pool_t *pool;
+    pj_xml_node *root;
+    char *output;
+    int output_len;
+
+    pool = pj_pool_create(mem, "xml", 4096, 1024, NULL);
+    pj_strdup2(pool, &msg, doc);
+    root = pj_xml_parse(pool, msg.ptr, msg.slen);
+    if (!root) {
+	PJ_LOG(1, (THIS_FILE, "  Error: unable to parse XML"));
+	return -10;
+    }
+
+    output = (char*)pj_pool_alloc(pool, msg.slen + 512);
+    pj_memset(output, 0, msg.slen+512);
+    output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE);
+    if (output_len < 1) {
+	PJ_LOG(1, (THIS_FILE, "  Error: buffer too small to print XML file"));
+	return -20;
+    }
+    output[output_len] = '\0';
+
+
+    pj_pool_release(pool);
+    return 0;
+}
+
+int xml_test()
+{
+    unsigned i;
+    for (i=0; i<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) {
+	int status;
+	if ((status=xml_parse_print_test(xml_doc[i])) != 0)
+	    return status;
+    }
+    return 0;
+}
+
+#else
+/* To prevent warning about "translation unit is empty"
+ * when this test is disabled. 
+ */
+int dummy_xml_test;
+#endif	/* INCLUDE_XML_TEST */
+
+
diff --git a/pjlib-util/src/pjlib-util/md5.c b/pjlib-util/src/pjlib-util/md5.c
index 80aed53..233a1da 100644
--- a/pjlib-util/src/pjlib-util/md5.c
+++ b/pjlib-util/src/pjlib-util/md5.c
@@ -1,279 +1,279 @@
-/* $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 <pjlib-util/md5.h>

-#include <pj/string.h>		/* pj_memcpy */

-/*

- * This code implements the MD5 message-digest algorithm.

- * The algorithm is due to Ron Rivest.  This code was

- * written by Colin Plumb in 1993, no copyright is claimed.

- * This code is in the public domain; do with it what you wish.

- *

- * Equivalent code is available from RSA Data Security, Inc.

- * This code has been tested against that, and is equivalent,

- * except that you don't need to include two pages of legalese

- * with every copy.

- *

- * To compute the message digest of a chunk of bytes, declare an

- * MD5Context structure, pass it to MD5Init, call MD5Update as

- * needed on buffers full of bytes, and then call MD5Final, which

- * will fill a supplied 16-byte array with the digest.

- */

-

-#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0

-#define HIGHFIRST 1

-#endif

-

-#ifndef HIGHFIRST

-#define byteReverse(buf, len)	/* Nothing */

-#else

-void byteReverse(unsigned char *buf, unsigned longs);

-

-#ifndef ASM_MD5

-/*

- * Note: this code is harmless on little-endian machines.

- */

-void byteReverse(unsigned char *buf, unsigned longs)

-{

-    pj_uint32_t t;

-    do {

-	t = (pj_uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |

-	    ((unsigned) buf[1] << 8 | buf[0]);

-	*(pj_uint32_t *) buf = t;

-	buf += 4;

-    } while (--longs);

-}

-#endif

-#endif

-

-static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16]);

-

-

-/*

- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious

- * initialization constants.

- */

-PJ_DEF(void) pj_md5_init(pj_md5_context *ctx)

-{

-    ctx->buf[0] = 0x67452301;

-    ctx->buf[1] = 0xefcdab89;

-    ctx->buf[2] = 0x98badcfe;

-    ctx->buf[3] = 0x10325476;

-

-    ctx->bits[0] = 0;

-    ctx->bits[1] = 0;

-}

-

-/*

- * Update context to reflect the concatenation of another buffer full

- * of bytes.

- */

-PJ_DEF(void) pj_md5_update( pj_md5_context *ctx, 

-			    unsigned char const *buf, unsigned len)

-{

-    pj_uint32_t t;

-

-    /* Update bitcount */

-

-    t = ctx->bits[0];

-    if ((ctx->bits[0] = t + ((pj_uint32_t) len << 3)) < t)

-	ctx->bits[1]++;		/* Carry from low to high */

-    ctx->bits[1] += len >> 29;

-

-    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */

-

-    /* Handle any leading odd-sized chunks */

-

-    if (t) {

-	unsigned char *p = (unsigned char *) ctx->in + t;

-

-	t = 64 - t;

-	if (len < t) {

-	    pj_memcpy(p, buf, len);

-	    return;

-	}

-	pj_memcpy(p, buf, t);

-	byteReverse(ctx->in, 16);

-	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);

-	buf += t;

-	len -= t;

-    }

-    /* Process data in 64-byte chunks */

-

-    while (len >= 64) {

-	pj_memcpy(ctx->in, buf, 64);

-	byteReverse(ctx->in, 16);

-	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);

-	buf += 64;

-	len -= 64;

-    }

-

-    /* Handle any remaining bytes of data. */

-

-    pj_memcpy(ctx->in, buf, len);

-}

-

-/*

- * Final wrapup - pad to 64-byte boundary with the bit pattern 

- * 1 0* (64-bit count of bits processed, MSB-first)

- */

-PJ_DEF(void) pj_md5_final(pj_md5_context *ctx, unsigned char digest[16])

-{

-    unsigned count;

-    unsigned char *p;

-

-    /* Compute number of bytes mod 64 */

-    count = (ctx->bits[0] >> 3) & 0x3F;

-

-    /* Set the first char of padding to 0x80.  This is safe since there is

-       always at least one byte free */

-    p = ctx->in + count;

-    *p++ = 0x80;

-

-    /* Bytes of padding needed to make 64 bytes */

-    count = 64 - 1 - count;

-

-    /* Pad out to 56 mod 64 */

-    if (count < 8) {

-	/* Two lots of padding:  Pad the first block to 64 bytes */

-	pj_memset(p, 0, count);

-	byteReverse(ctx->in, 16);

-	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);

-

-	/* Now fill the next block with 56 bytes */

-	pj_memset(ctx->in, 0, 56);

-    } else {

-	/* Pad block to 56 bytes */

-	pj_memset(p, 0, count - 8);

-    }

-    byteReverse(ctx->in, 14);

-

-    /* Append length in bits and transform */

-    ((pj_uint32_t *) ctx->in)[14] = ctx->bits[0];

-    ((pj_uint32_t *) ctx->in)[15] = ctx->bits[1];

-

-    MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);

-    byteReverse((unsigned char *) ctx->buf, 4);

-    pj_memcpy(digest, ctx->buf, 16);

-    pj_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */

-}

-

-#ifndef ASM_MD5

-

-/* The four core functions - F1 is optimized somewhat */

-

-/* #define F1(x, y, z) (x & y | ~x & z) */

-#define F1(x, y, z) (z ^ (x & (y ^ z)))

-#define F2(x, y, z) F1(z, x, y)

-#define F3(x, y, z) (x ^ y ^ z)

-#define F4(x, y, z) (y ^ (x | ~z))

-

-/* This is the central step in the MD5 algorithm. */

-#define MD5STEP(f, w, x, y, z, data, s) \

-	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )

-

-/*

- * The core of the MD5 algorithm, this alters an existing MD5 hash to

- * reflect the addition of 16 longwords of new data.  MD5Update blocks

- * the data and converts bytes into longwords for this routine.

- */

-static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16])

-{

-    register pj_uint32_t a, b, c, d;

-

-    a = buf[0];

-    b = buf[1];

-    c = buf[2];

-    d = buf[3];

-

-    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);

-    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);

-    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);

-    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);

-    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);

-    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);

-    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);

-    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);

-    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);

-    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);

-    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);

-    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);

-    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);

-    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);

-    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);

-    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

-

-    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);

-    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);

-    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);

-    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);

-    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);

-    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);

-    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);

-    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);

-    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);

-    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);

-    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);

-    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);

-    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);

-    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);

-    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);

-    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

-

-    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);

-    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);

-    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);

-    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);

-    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);

-    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);

-    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);

-    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);

-    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);

-    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);

-    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);

-    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);

-    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);

-    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);

-    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);

-    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);

-

-    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);

-    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);

-    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);

-    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);

-    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);

-    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);

-    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);

-    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);

-    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);

-    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);

-    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);

-    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);

-    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);

-    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);

-    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);

-    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);

-

-    buf[0] += a;

-    buf[1] += b;

-    buf[2] += c;

-    buf[3] += d;

-}

-

-#endif

-

+/* $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 <pjlib-util/md5.h>
+#include <pj/string.h>		/* pj_memcpy */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0
+#define HIGHFIRST 1
+#endif
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)	/* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    pj_uint32_t t;
+    do {
+	t = (pj_uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(pj_uint32_t *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+#endif
+#endif
+
+static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16]);
+
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+PJ_DEF(void) pj_md5_init(pj_md5_context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+PJ_DEF(void) pj_md5_update( pj_md5_context *ctx, 
+			    unsigned char const *buf, unsigned len)
+{
+    pj_uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((pj_uint32_t) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    pj_memcpy(p, buf, len);
+	    return;
+	}
+	pj_memcpy(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	pj_memcpy(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    pj_memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+PJ_DEF(void) pj_md5_final(pj_md5_context *ctx, unsigned char digest[16])
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	pj_memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	pj_memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	pj_memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((pj_uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((pj_uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    pj_memcpy(digest, ctx->buf, 16);
+    pj_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16])
+{
+    register pj_uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+#endif
+
diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c
index 27a1d4d..3a19e9f 100644
--- a/pjlib-util/src/pjlib-util/scanner.c
+++ b/pjlib-util/src/pjlib-util/scanner.c
@@ -1,595 +1,595 @@
-/* $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 <pjlib-util/scanner.h>

-#include <pj/string.h>

-#include <pj/except.h>

-#include <pj/os.h>

-#include <pj/errno.h>

-

-#define PJ_SCAN_IS_SPACE(c)	((c)==' ' || (c)=='\t')

-#define PJ_SCAN_IS_NEWLINE(c)	((c)=='\r' || (c)=='\n')

-#define PJ_SCAN_CHECK_EOF(s)	(s != end)

-

-

-static void pj_scan_syntax_err(pj_scanner *scanner)

-{

-    (*scanner->callback)(scanner);

-}

-

-PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf)

-{

-    pj_memset(cis_buf->cis_buf, 0, sizeof(cis_buf->cis_buf));

-    cis_buf->use_mask = 0;

-}

-

-PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis)

-{

-    unsigned i;

-

-    cis->cis_buf = cis_buf->cis_buf;

-

-    for (i=0; i<PJ_CIS_MAX_INDEX; ++i) {

-        if ((cis_buf->use_mask & (1 << i)) == 0) {

-            cis->cis_id = i;

-	    cis_buf->use_mask |= (1 << i);

-            return PJ_SUCCESS;

-        }

-    }

-

-    cis->cis_id = PJ_CIS_MAX_INDEX;

-    return PJ_ETOOMANY;

-}

-

-PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing)

-{

-    pj_status_t status;

-    unsigned i;

-

-    /* Warning: typecasting here! */

-    status = pj_cis_init((pj_cis_buf_t*)existing->cis_buf, new_cis);

-    if (status != PJ_SUCCESS)

-        return status;

-

-    for (i=0; i<256; ++i) {

-        if (PJ_CIS_ISSET(existing, i))

-            PJ_CIS_SET(new_cis, i);

-        else

-            PJ_CIS_CLR(new_cis, i);

-    }

-

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend)

-{

-    while (cstart != cend) {

-        PJ_CIS_SET(cis, cstart);

-	++cstart;

-    }

-}

-

-PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis)

-{

-    pj_cis_add_range( cis, 'a', 'z'+1);

-    pj_cis_add_range( cis, 'A', 'Z'+1);

-}

-

-PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis)

-{

-    pj_cis_add_range( cis, '0', '9'+1);

-}

-

-PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str)

-{

-    while (*str) {

-        PJ_CIS_SET(cis, *str);

-	++str;

-    }

-}

-

-PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend)

-{

-    while (cstart != cend) {

-        PJ_CIS_CLR(cis, cstart);

-        cstart++;

-    }

-}

-

-PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str)

-{

-    while (*str) {

-        PJ_CIS_CLR(cis, *str);

-	++str;

-    }

-}

-

-PJ_DEF(void) pj_cis_invert( pj_cis_t *cis )

-{

-    unsigned i;

-    for (i=0; i<256; ++i) {

-	if (PJ_CIS_ISSET(cis,i))

-            PJ_CIS_CLR(cis,i);

-        else

-            PJ_CIS_SET(cis,i);

-    }

-}

-

-PJ_DEF(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 

-			   unsigned options, pj_syn_err_func_ptr callback )

-{

-    PJ_CHECK_STACK();

-

-    scanner->begin = scanner->curptr = bufstart;

-    scanner->end = bufstart + buflen;

-    scanner->line = 1;

-    scanner->col = 1;

-    scanner->callback = callback;

-    scanner->skip_ws = options;

-

-    if (scanner->skip_ws) 

-	pj_scan_skip_whitespace(scanner);

-

-    scanner->col = scanner->curptr - scanner->begin + 1;

-}

-

-

-PJ_DEF(void) pj_scan_fini( pj_scanner *scanner )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(scanner);

-}

-

-PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )

-{

-    register char *s = scanner->curptr;

-

-    PJ_CHECK_STACK();

-

-    while (PJ_SCAN_IS_SPACE(*s)) {

-	++s;

-    }

-

-    if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) {

-	for (;;) {

-	    if (*s == '\r') {

-		++s;

-		if (*s == '\n') ++s;

-		++scanner->line;

-		scanner->col = 1;

-		scanner->curptr = s;

-	    } else if (*s == '\n') {

-		++s;

-		++scanner->line;

-		scanner->col = 1;

-		scanner->curptr = s;

-	    } else if (PJ_SCAN_IS_SPACE(*s)) {

-		do {

-		    ++s;

-		} while (PJ_SCAN_IS_SPACE(*s));

-	    } else {

-		break;

-	    }

-	}

-    }

-

-    if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) {

-	/* Check for header continuation. */

-	scanner->col += s - scanner->curptr;

-	scanner->curptr = s;

-

-	if (*s == '\r') {

-	    ++s;

-	}

-	if (*s == '\n') {

-	    ++s;

-	}

-	if (PJ_SCAN_IS_SPACE(*s)) {

-	    register char *t = s;

-	    do {

-		++t;

-	    } while (PJ_SCAN_IS_SPACE(*t));

-

-	    ++scanner->line;

-	    scanner->col = t-s;

-	    scanner->curptr = t;

-	}

-    } else {

-	scanner->col += s - scanner->curptr;

-	scanner->curptr = s;

-    }

-}

-

-PJ_DEF(int) pj_scan_peek( pj_scanner *scanner,

-			  const pj_cis_t *spec, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return -1;

-    }

-

-    while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s))

-	++s;

-

-    pj_strset3(out, scanner->curptr, s);

-    return s < scanner->end ? *s : 0;

-}

-

-

-PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner,

-			     pj_size_t len, pj_str_t *out)

-{

-    char *endpos = scanner->curptr + len;

-

-    PJ_CHECK_STACK();

-

-    if (endpos > scanner->end) {

-	pj_scan_syntax_err(scanner);

-	return -1;

-    }

-

-    pj_strset(out, scanner->curptr, len);

-    return *endpos;

-}

-

-

-PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner,

-				const pj_cis_t *spec, 

-				pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return -1;

-    }

-

-    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s))

-	++s;

-

-    pj_strset3(out, scanner->curptr, s);

-    return s!=scanner->end ? *s : 0;

-}

-

-

-PJ_DEF(void) pj_scan_get( pj_scanner *scanner,

-			  const pj_cis_t *spec, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-    char *start = s;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    do {

-	++s;

-    } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));

-

-    pj_strset3(out, scanner->curptr, s);

-

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);    

-    }

-}

-

-

-PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner,

-				 int begin_quote, int end_quote, 

-				 pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-    char *start = s;

-    

-    PJ_CHECK_STACK();

-

-    /* Check and eat the begin_quote. */

-    if (*s != begin_quote) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-    ++s;

-

-    /* Loop until end_quote is found. 

-     */

-    do {

-	/* loop until end_quote is found. */

-	do {

-	    ++s;

-	} while (s != end && *s != '\n' && *s != end_quote);

-

-	/* check that no backslash character precedes the end_quote. */

-	if (*s == end_quote) {

-	    if (*(s-1) == '\\') {

-		if (s-2 == scanner->begin) {

-		    break;

-		} else {

-		    char *q = s-2;

-		    char *r = s-2;

-

-		    while (r != scanner->begin && *r == '\\') {

-			--r;

-		    }

-		    /* break from main loop if we have odd number of backslashes */

-		    if (((unsigned)(q-r) & 0x01) == 1) {

-			break;

-		    }

-		}

-	    } else {

-		/* end_quote is not preceeded by backslash. break now. */

-		break;

-	    }

-	} else {

-	    /* loop ended by non-end_quote character. break now. */

-	    break;

-	}

-    } while (1);

-

-    /* Check and eat the end quote. */

-    if (*s != end_quote) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-    ++s;

-

-    pj_strset3(out, scanner->curptr, s);

-

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner,

-			     unsigned N, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    char *start = scanner->curptr;

-

-    PJ_CHECK_STACK();

-

-    if (scanner->curptr + N > scanner->end) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    pj_strset(out, s, N);

-    

-    s += N;

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-

-PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner )

-{

-    char *start = scanner->curptr;

-    int chr = *start;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return 0;

-    }

-

-    ++scanner->curptr;

-    scanner->col += (scanner->curptr - start);

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-    return chr;

-}

-

-

-PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner )

-{

-    PJ_CHECK_STACK();

-

-    if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    if (*scanner->curptr == '\r') {

-	++scanner->curptr;

-    }

-    if (*scanner->curptr == '\n') {

-	++scanner->curptr;

-    }

-

-    ++scanner->line;

-    scanner->col = 1;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-

-PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner,

-				const pj_cis_t *spec, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-    char *start = s;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) {

-	++s;

-    }

-

-    pj_strset3(out, scanner->curptr, s);

-

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-

-PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, 

-				   int until_char, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-    char *start = s;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) {

-	++s;

-    }

-

-    pj_strset3(out, scanner->curptr, s);

-

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-

-PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner,

-				     const char *until_spec, pj_str_t *out)

-{

-    register char *s = scanner->curptr;

-    register char *end = scanner->end;

-    char *start = scanner->curptr;

-

-    PJ_CHECK_STACK();

-

-    if (pj_scan_is_eof(scanner)) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) {

-	++s;

-    }

-

-    pj_strset3(out, scanner->curptr, s);

-

-    scanner->col += (s - start);

-    scanner->curptr = s;

-

-    if (scanner->skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner,

-				 unsigned N, pj_bool_t skip_ws)

-{

-    char *start = scanner->curptr;

-

-    PJ_CHECK_STACK();

-

-    if (scanner->curptr + N > scanner->end) {

-	pj_scan_syntax_err(scanner);

-	return;

-    }

-

-    scanner->curptr += N;

-    scanner->col += (scanner->curptr - start);

-

-    if (skip_ws) {

-	pj_scan_skip_whitespace(scanner);

-    }

-}

-

-

-PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len)

-{

-    if (scanner->curptr + len > scanner->end) {

-	pj_scan_syntax_err(scanner);

-	return -1;

-    }

-    return strncmp(scanner->curptr, s, len);

-}

-

-

-PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len)

-{

-    if (scanner->curptr + len > scanner->end) {

-	pj_scan_syntax_err(scanner);

-	return -1;

-    }

-    return strnicmp(scanner->curptr, s, len);

-}

-

-

-PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state)

-{

-    PJ_CHECK_STACK();

-

-    state->curptr = scanner->curptr;

-    state->line = scanner->line;

-    state->col = scanner->col;

-}

-

-

-PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, 

-				     pj_scan_state *state)

-{

-    PJ_CHECK_STACK();

-

-    scanner->curptr = state->curptr;

-    scanner->line = state->line;

-    scanner->col = state->col;

-}

-

-

+/* $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 <pjlib-util/scanner.h>
+#include <pj/string.h>
+#include <pj/except.h>
+#include <pj/os.h>
+#include <pj/errno.h>
+
+#define PJ_SCAN_IS_SPACE(c)	((c)==' ' || (c)=='\t')
+#define PJ_SCAN_IS_NEWLINE(c)	((c)=='\r' || (c)=='\n')
+#define PJ_SCAN_CHECK_EOF(s)	(s != end)
+
+
+static void pj_scan_syntax_err(pj_scanner *scanner)
+{
+    (*scanner->callback)(scanner);
+}
+
+PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf)
+{
+    pj_memset(cis_buf->cis_buf, 0, sizeof(cis_buf->cis_buf));
+    cis_buf->use_mask = 0;
+}
+
+PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis)
+{
+    unsigned i;
+
+    cis->cis_buf = cis_buf->cis_buf;
+
+    for (i=0; i<PJ_CIS_MAX_INDEX; ++i) {
+        if ((cis_buf->use_mask & (1 << i)) == 0) {
+            cis->cis_id = i;
+	    cis_buf->use_mask |= (1 << i);
+            return PJ_SUCCESS;
+        }
+    }
+
+    cis->cis_id = PJ_CIS_MAX_INDEX;
+    return PJ_ETOOMANY;
+}
+
+PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing)
+{
+    pj_status_t status;
+    unsigned i;
+
+    /* Warning: typecasting here! */
+    status = pj_cis_init((pj_cis_buf_t*)existing->cis_buf, new_cis);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    for (i=0; i<256; ++i) {
+        if (PJ_CIS_ISSET(existing, i))
+            PJ_CIS_SET(new_cis, i);
+        else
+            PJ_CIS_CLR(new_cis, i);
+    }
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend)
+{
+    while (cstart != cend) {
+        PJ_CIS_SET(cis, cstart);
+	++cstart;
+    }
+}
+
+PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis)
+{
+    pj_cis_add_range( cis, 'a', 'z'+1);
+    pj_cis_add_range( cis, 'A', 'Z'+1);
+}
+
+PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis)
+{
+    pj_cis_add_range( cis, '0', '9'+1);
+}
+
+PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str)
+{
+    while (*str) {
+        PJ_CIS_SET(cis, *str);
+	++str;
+    }
+}
+
+PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend)
+{
+    while (cstart != cend) {
+        PJ_CIS_CLR(cis, cstart);
+        cstart++;
+    }
+}
+
+PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str)
+{
+    while (*str) {
+        PJ_CIS_CLR(cis, *str);
+	++str;
+    }
+}
+
+PJ_DEF(void) pj_cis_invert( pj_cis_t *cis )
+{
+    unsigned i;
+    for (i=0; i<256; ++i) {
+	if (PJ_CIS_ISSET(cis,i))
+            PJ_CIS_CLR(cis,i);
+        else
+            PJ_CIS_SET(cis,i);
+    }
+}
+
+PJ_DEF(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 
+			   unsigned options, pj_syn_err_func_ptr callback )
+{
+    PJ_CHECK_STACK();
+
+    scanner->begin = scanner->curptr = bufstart;
+    scanner->end = bufstart + buflen;
+    scanner->line = 1;
+    scanner->col = 1;
+    scanner->callback = callback;
+    scanner->skip_ws = options;
+
+    if (scanner->skip_ws) 
+	pj_scan_skip_whitespace(scanner);
+
+    scanner->col = scanner->curptr - scanner->begin + 1;
+}
+
+
+PJ_DEF(void) pj_scan_fini( pj_scanner *scanner )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(scanner);
+}
+
+PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )
+{
+    register char *s = scanner->curptr;
+
+    PJ_CHECK_STACK();
+
+    while (PJ_SCAN_IS_SPACE(*s)) {
+	++s;
+    }
+
+    if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) {
+	for (;;) {
+	    if (*s == '\r') {
+		++s;
+		if (*s == '\n') ++s;
+		++scanner->line;
+		scanner->col = 1;
+		scanner->curptr = s;
+	    } else if (*s == '\n') {
+		++s;
+		++scanner->line;
+		scanner->col = 1;
+		scanner->curptr = s;
+	    } else if (PJ_SCAN_IS_SPACE(*s)) {
+		do {
+		    ++s;
+		} while (PJ_SCAN_IS_SPACE(*s));
+	    } else {
+		break;
+	    }
+	}
+    }
+
+    if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) {
+	/* Check for header continuation. */
+	scanner->col += s - scanner->curptr;
+	scanner->curptr = s;
+
+	if (*s == '\r') {
+	    ++s;
+	}
+	if (*s == '\n') {
+	    ++s;
+	}
+	if (PJ_SCAN_IS_SPACE(*s)) {
+	    register char *t = s;
+	    do {
+		++t;
+	    } while (PJ_SCAN_IS_SPACE(*t));
+
+	    ++scanner->line;
+	    scanner->col = t-s;
+	    scanner->curptr = t;
+	}
+    } else {
+	scanner->col += s - scanner->curptr;
+	scanner->curptr = s;
+    }
+}
+
+PJ_DEF(int) pj_scan_peek( pj_scanner *scanner,
+			  const pj_cis_t *spec, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return -1;
+    }
+
+    while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s))
+	++s;
+
+    pj_strset3(out, scanner->curptr, s);
+    return s < scanner->end ? *s : 0;
+}
+
+
+PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner,
+			     pj_size_t len, pj_str_t *out)
+{
+    char *endpos = scanner->curptr + len;
+
+    PJ_CHECK_STACK();
+
+    if (endpos > scanner->end) {
+	pj_scan_syntax_err(scanner);
+	return -1;
+    }
+
+    pj_strset(out, scanner->curptr, len);
+    return *endpos;
+}
+
+
+PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner,
+				const pj_cis_t *spec, 
+				pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return -1;
+    }
+
+    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s))
+	++s;
+
+    pj_strset3(out, scanner->curptr, s);
+    return s!=scanner->end ? *s : 0;
+}
+
+
+PJ_DEF(void) pj_scan_get( pj_scanner *scanner,
+			  const pj_cis_t *spec, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+    char *start = s;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    do {
+	++s;
+    } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));
+
+    pj_strset3(out, scanner->curptr, s);
+
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);    
+    }
+}
+
+
+PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner,
+				 int begin_quote, int end_quote, 
+				 pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+    char *start = s;
+    
+    PJ_CHECK_STACK();
+
+    /* Check and eat the begin_quote. */
+    if (*s != begin_quote) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+    ++s;
+
+    /* Loop until end_quote is found. 
+     */
+    do {
+	/* loop until end_quote is found. */
+	do {
+	    ++s;
+	} while (s != end && *s != '\n' && *s != end_quote);
+
+	/* check that no backslash character precedes the end_quote. */
+	if (*s == end_quote) {
+	    if (*(s-1) == '\\') {
+		if (s-2 == scanner->begin) {
+		    break;
+		} else {
+		    char *q = s-2;
+		    char *r = s-2;
+
+		    while (r != scanner->begin && *r == '\\') {
+			--r;
+		    }
+		    /* break from main loop if we have odd number of backslashes */
+		    if (((unsigned)(q-r) & 0x01) == 1) {
+			break;
+		    }
+		}
+	    } else {
+		/* end_quote is not preceeded by backslash. break now. */
+		break;
+	    }
+	} else {
+	    /* loop ended by non-end_quote character. break now. */
+	    break;
+	}
+    } while (1);
+
+    /* Check and eat the end quote. */
+    if (*s != end_quote) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+    ++s;
+
+    pj_strset3(out, scanner->curptr, s);
+
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner,
+			     unsigned N, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    char *start = scanner->curptr;
+
+    PJ_CHECK_STACK();
+
+    if (scanner->curptr + N > scanner->end) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    pj_strset(out, s, N);
+    
+    s += N;
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+
+PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner )
+{
+    char *start = scanner->curptr;
+    int chr = *start;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return 0;
+    }
+
+    ++scanner->curptr;
+    scanner->col += (scanner->curptr - start);
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+    return chr;
+}
+
+
+PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner )
+{
+    PJ_CHECK_STACK();
+
+    if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    if (*scanner->curptr == '\r') {
+	++scanner->curptr;
+    }
+    if (*scanner->curptr == '\n') {
+	++scanner->curptr;
+    }
+
+    ++scanner->line;
+    scanner->col = 1;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+
+PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner,
+				const pj_cis_t *spec, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+    char *start = s;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) {
+	++s;
+    }
+
+    pj_strset3(out, scanner->curptr, s);
+
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+
+PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, 
+				   int until_char, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+    char *start = s;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) {
+	++s;
+    }
+
+    pj_strset3(out, scanner->curptr, s);
+
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+
+PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner,
+				     const char *until_spec, pj_str_t *out)
+{
+    register char *s = scanner->curptr;
+    register char *end = scanner->end;
+    char *start = scanner->curptr;
+
+    PJ_CHECK_STACK();
+
+    if (pj_scan_is_eof(scanner)) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) {
+	++s;
+    }
+
+    pj_strset3(out, scanner->curptr, s);
+
+    scanner->col += (s - start);
+    scanner->curptr = s;
+
+    if (scanner->skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner,
+				 unsigned N, pj_bool_t skip_ws)
+{
+    char *start = scanner->curptr;
+
+    PJ_CHECK_STACK();
+
+    if (scanner->curptr + N > scanner->end) {
+	pj_scan_syntax_err(scanner);
+	return;
+    }
+
+    scanner->curptr += N;
+    scanner->col += (scanner->curptr - start);
+
+    if (skip_ws) {
+	pj_scan_skip_whitespace(scanner);
+    }
+}
+
+
+PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len)
+{
+    if (scanner->curptr + len > scanner->end) {
+	pj_scan_syntax_err(scanner);
+	return -1;
+    }
+    return strncmp(scanner->curptr, s, len);
+}
+
+
+PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len)
+{
+    if (scanner->curptr + len > scanner->end) {
+	pj_scan_syntax_err(scanner);
+	return -1;
+    }
+    return strnicmp(scanner->curptr, s, len);
+}
+
+
+PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state)
+{
+    PJ_CHECK_STACK();
+
+    state->curptr = scanner->curptr;
+    state->line = scanner->line;
+    state->col = scanner->col;
+}
+
+
+PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, 
+				     pj_scan_state *state)
+{
+    PJ_CHECK_STACK();
+
+    scanner->curptr = state->curptr;
+    scanner->line = state->line;
+    scanner->col = state->col;
+}
+
+
diff --git a/pjlib-util/src/pjlib-util/string.c b/pjlib-util/src/pjlib-util/string.c
index 55859eb..8115bc8 100644
--- a/pjlib-util/src/pjlib-util/string.c
+++ b/pjlib-util/src/pjlib-util/string.c
@@ -1,99 +1,107 @@
-/* $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 <pjlib-util/string.h>

-#include <pj/ctype.h>

-

-PJ_DEF(void) pj_str_unescape(pj_str_t *str)

-{

-    char *src = str->ptr;

-    char *dst = str->ptr;

-    char *end = src + str->slen;

-    

-    while (src != end) {

-	if (*src == '%' && src < end-2) {

-	    *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + 

-				 pj_hex_digit_to_val(*(src+2)));

-	    ++dst;

-	    src += 3;

-	} else {

-	    ++src;

-	    ++dst;

-	}

-    }

-    str->slen = dst - str->ptr;

-}

-

-PJ_DEF(pj_str_t*) pj_strcpy_unescape(pj_str_t *dst_str,

-				     const pj_str_t *src_str)

-{

-    const char *src = src_str->ptr;

-    const char *end = src + src_str->slen;

-    char *dst = dst_str->ptr;

-    

-    while (src != end) {

-	if (*src == '%' && src < end-2) {

-	    *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + 

-				 pj_hex_digit_to_val(*(src+2)));

-	    ++dst;

-	    src += 3;

-	} else {

-	    *dst++ = *src++;

-	}

-    }

-    dst_str->slen = dst - dst_str->ptr;

-    return dst_str;

-}

-

-PJ_DEF(pj_ssize_t) pj_strncpy2_escape( char *dst_str, const pj_str_t *src_str,

-				       pj_ssize_t max, const pj_cis_t *unres)

-{

-    const char *src = src_str->ptr;

-    const char *src_end = src + src_str->slen;

-    char *dst = dst_str;

-    char *dst_end = dst + max;

-

-    if (max < src_str->slen)

-	return -1;

-

-    while (src != src_end && dst != dst_end) {

-	if (pj_cis_match(unres, *src)) {

-	    *dst++ = *src++;

-	} else {

-	    if (dst < dst_end-2) {

-		*dst++ = '%';

-		pj_val_to_hex_digit(*src, dst);

-		dst+=2;

-		++src;

-	    } else {

-		break;

-	    }

-	}

-    }

-

-    return src==src_end ? dst-dst_str : -1;

-}

-

-PJ_DEF(pj_str_t*) pj_strncpy_escape(pj_str_t *dst_str, 

-				    const pj_str_t *src_str,

-				    pj_ssize_t max, const pj_cis_t *unres)

-{

-    dst_str->slen = pj_strncpy2_escape(dst_str->ptr, src_str, max, unres);

-    return dst_str->slen < 0 ? NULL : dst_str;

-}

-

+/* $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 <pjlib-util/string.h>
+#include <pj/ctype.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+
+PJ_DEF(pj_str_t) pj_str_unescape( pj_pool_t *pool, const pj_str_t *src_str)
+{
+    char *src = src_str->ptr;
+    char *end = src + src_str->slen;
+    pj_str_t dst_str;
+    char *dst;
+    
+    if (pj_strchr(src_str, '%')==NULL)
+	return *src_str;
+
+    dst = dst_str.ptr = pj_pool_alloc(pool, src_str->slen);
+
+    while (src != end) {
+	if (*src == '%' && src < end-2) {
+	    *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + 
+				 pj_hex_digit_to_val(*(src+2)));
+	    ++dst;
+	    src += 3;
+	} else {
+	    *dst++ = *src++;
+	}
+    }
+    dst_str.slen = dst - dst_str.ptr;
+    return dst_str;
+}
+
+PJ_DEF(pj_str_t*) pj_strcpy_unescape(pj_str_t *dst_str,
+				     const pj_str_t *src_str)
+{
+    const char *src = src_str->ptr;
+    const char *end = src + src_str->slen;
+    char *dst = dst_str->ptr;
+    
+    while (src != end) {
+	if (*src == '%' && src < end-2) {
+	    *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + 
+				 pj_hex_digit_to_val(*(src+2)));
+	    ++dst;
+	    src += 3;
+	} else {
+	    *dst++ = *src++;
+	}
+    }
+    dst_str->slen = dst - dst_str->ptr;
+    return dst_str;
+}
+
+PJ_DEF(pj_ssize_t) pj_strncpy2_escape( char *dst_str, const pj_str_t *src_str,
+				       pj_ssize_t max, const pj_cis_t *unres)
+{
+    const char *src = src_str->ptr;
+    const char *src_end = src + src_str->slen;
+    char *dst = dst_str;
+    char *dst_end = dst + max;
+
+    if (max < src_str->slen)
+	return -1;
+
+    while (src != src_end && dst != dst_end) {
+	if (pj_cis_match(unres, *src)) {
+	    *dst++ = *src++;
+	} else {
+	    if (dst < dst_end-2) {
+		*dst++ = '%';
+		pj_val_to_hex_digit(*src, dst);
+		dst+=2;
+		++src;
+	    } else {
+		break;
+	    }
+	}
+    }
+
+    return src==src_end ? dst-dst_str : -1;
+}
+
+PJ_DEF(pj_str_t*) pj_strncpy_escape(pj_str_t *dst_str, 
+				    const pj_str_t *src_str,
+				    pj_ssize_t max, const pj_cis_t *unres)
+{
+    dst_str->slen = pj_strncpy2_escape(dst_str->ptr, src_str, max, unres);
+    return dst_str->slen < 0 ? NULL : dst_str;
+}
+
diff --git a/pjlib-util/src/pjlib-util/stun.c b/pjlib-util/src/pjlib-util/stun.c
index f428769..52c5bf5 100644
--- a/pjlib-util/src/pjlib-util/stun.c
+++ b/pjlib-util/src/pjlib-util/stun.c
@@ -1,129 +1,129 @@
-/* $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 <pjlib-util/stun.h>

-#include <pj/pool.h>

-#include <pj/log.h>

-#include <pj/sock.h>

-#include <pj/os.h>

-

-#define THIS_FILE   "stun"

-

-PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 

-					     void **msg, pj_size_t *len,

-					     pj_uint32_t id_hi, 

-					     pj_uint32_t id_lo)

-{

-    pj_stun_msg_hdr *hdr;

-    

-    PJ_CHECK_STACK();

-

-    PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req"));

-

-    hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr));

-    if (!hdr) {

-	PJ_LOG(5,(THIS_FILE, "Error allocating memory!"));

-	return -1;

-    }

-

-    hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST);

-    hdr->tsx[2] = pj_htonl(id_hi);

-    hdr->tsx[3] = pj_htonl(id_lo);

-    *msg = hdr;

-    *len = sizeof(pj_stun_msg_hdr);

-

-    return 0;

-}

-

-PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, 

-				       pj_stun_msg *msg)

-{

-    pj_uint16_t msg_type, msg_len;

-    char *p_attr;

-

-    PJ_CHECK_STACK();

-

-    PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len));

-

-    msg->hdr = (pj_stun_msg_hdr*)buf;

-    msg_type = pj_ntohs(msg->hdr->type);

-

-    switch (msg_type) {

-    case PJ_STUN_BINDING_REQUEST:

-    case PJ_STUN_BINDING_RESPONSE:

-    case PJ_STUN_BINDING_ERROR_RESPONSE:

-    case PJ_STUN_SHARED_SECRET_REQUEST:

-    case PJ_STUN_SHARED_SECRET_RESPONSE:

-    case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE:

-	break;

-    default:

-	PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type));

-	return -1;

-    }

-

-    msg_len = pj_ntohs(msg->hdr->length);

-    if (msg_len != len - sizeof(pj_stun_msg_hdr)) {

-	PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", 

-			     msg_len, len - sizeof(pj_stun_msg_hdr)));

-	return -1;

-    }

-

-    msg->attr_count = 0;

-    p_attr = (char*)buf + sizeof(pj_stun_msg_hdr);

-

-    while (msg_len > 0) {

-	pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count];

-	pj_uint32_t len;

-

-	*attr = (pj_stun_attr_hdr*)p_attr;

-	len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr);

-

-	if (msg_len < len) {

-	    PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", 

-				 msg->attr_count));

-	    return -1;

-	}

-

-	if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) {

-	    PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d",

-				 pj_ntohs((*attr)->type), msg->attr_count));

-	    return -1;

-	}

-

-	msg_len = (pj_uint16_t)(msg_len - len);

-	p_attr += len;

-	++msg->attr_count;

-    }

-

-    return 0;

-}

-

-PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t)

-{

-    int i;

-

-    PJ_CHECK_STACK();

-

-    for (i=0; i<msg->attr_count; ++i) {

-	pj_stun_attr_hdr *attr = msg->attr[i];

-	if (pj_ntohs(attr->type) == t)

-	    return attr;

-    }

-

-    return 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 <pjlib-util/stun.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/sock.h>
+#include <pj/os.h>
+
+#define THIS_FILE   "stun"
+
+PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 
+					     void **msg, pj_size_t *len,
+					     pj_uint32_t id_hi, 
+					     pj_uint32_t id_lo)
+{
+    pj_stun_msg_hdr *hdr;
+    
+    PJ_CHECK_STACK();
+
+    PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req"));
+
+    hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr));
+    if (!hdr) {
+	PJ_LOG(5,(THIS_FILE, "Error allocating memory!"));
+	return -1;
+    }
+
+    hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST);
+    hdr->tsx[2] = pj_htonl(id_hi);
+    hdr->tsx[3] = pj_htonl(id_lo);
+    *msg = hdr;
+    *len = sizeof(pj_stun_msg_hdr);
+
+    return 0;
+}
+
+PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, 
+				       pj_stun_msg *msg)
+{
+    pj_uint16_t msg_type, msg_len;
+    char *p_attr;
+
+    PJ_CHECK_STACK();
+
+    PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len));
+
+    msg->hdr = (pj_stun_msg_hdr*)buf;
+    msg_type = pj_ntohs(msg->hdr->type);
+
+    switch (msg_type) {
+    case PJ_STUN_BINDING_REQUEST:
+    case PJ_STUN_BINDING_RESPONSE:
+    case PJ_STUN_BINDING_ERROR_RESPONSE:
+    case PJ_STUN_SHARED_SECRET_REQUEST:
+    case PJ_STUN_SHARED_SECRET_RESPONSE:
+    case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE:
+	break;
+    default:
+	PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type));
+	return -1;
+    }
+
+    msg_len = pj_ntohs(msg->hdr->length);
+    if (msg_len != len - sizeof(pj_stun_msg_hdr)) {
+	PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", 
+			     msg_len, len - sizeof(pj_stun_msg_hdr)));
+	return -1;
+    }
+
+    msg->attr_count = 0;
+    p_attr = (char*)buf + sizeof(pj_stun_msg_hdr);
+
+    while (msg_len > 0) {
+	pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count];
+	pj_uint32_t len;
+
+	*attr = (pj_stun_attr_hdr*)p_attr;
+	len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr);
+
+	if (msg_len < len) {
+	    PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", 
+				 msg->attr_count));
+	    return -1;
+	}
+
+	if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) {
+	    PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d",
+				 pj_ntohs((*attr)->type), msg->attr_count));
+	    return -1;
+	}
+
+	msg_len = (pj_uint16_t)(msg_len - len);
+	p_attr += len;
+	++msg->attr_count;
+    }
+
+    return 0;
+}
+
+PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t)
+{
+    int i;
+
+    PJ_CHECK_STACK();
+
+    for (i=0; i<msg->attr_count; ++i) {
+	pj_stun_attr_hdr *attr = msg->attr[i];
+	if (pj_ntohs(attr->type) == t)
+	    return attr;
+    }
+
+    return 0;
+}
diff --git a/pjlib-util/src/pjlib-util/stun_client.c b/pjlib-util/src/pjlib-util/stun_client.c
index e0633cc..69153f6 100644
--- a/pjlib-util/src/pjlib-util/stun_client.c
+++ b/pjlib-util/src/pjlib-util/stun_client.c
@@ -1,277 +1,277 @@
-/* $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 <pjlib-util/stun.h>

-#include <pj/pool.h>

-#include <pj/log.h>

-#include <pj/string.h>

-#include <pj/os.h>

-#include <pj/sock_select.h>

-

-enum { MAX_REQUEST = 3 };

-static int stun_timer[] = {1600, 1600, 1600 };

-

-#define THIS_FILE	"stunclient"

-#define LOG_ADDR(addr)	pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port)

-

-

-PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,

-					      int sock_cnt, pj_sock_t sock[],

-					      const pj_str_t *srv1, int port1,

-					      const pj_str_t *srv2, int port2,

-					      pj_sockaddr_in mapped_addr[])

-{

-    pj_sockaddr_in srv_addr[2];

-    int i, j, rc, send_cnt = 0;

-    pj_pool_t *pool;

-    struct {

-	struct {

-	    pj_uint32_t	mapped_addr;

-	    pj_uint32_t	mapped_port;

-	} srv[2];

-    } *rec;

-    void       *out_msg;

-    pj_size_t	out_msg_len;

-    int wait_resp = 0;

-    int mapped_status = 0;

-

-    PJ_CHECK_STACK();

-

-    /* Create pool. */

-    pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL);

-    if (!pool) {

-	mapped_status = PJ_STUN_ERR_MEMORY; 

-	return -1;

-    }

-

-    /* Allocate client records */

-    rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec));

-    if (!rec) {

-	mapped_status = PJ_STUN_ERR_MEMORY; 

-	goto on_error;

-    }

-

-    /* Create the outgoing BIND REQUEST message template */

-    rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0);

-    if (rc != 0) {

-	mapped_status = -1;

-	goto on_error;

-    }

-

-    /* Resolve servers. */

-    if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) {

-	mapped_status = PJ_STUN_ERR_RESOLVE; 

-	goto on_error;

-    }

-    if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) {

-	mapped_status = PJ_STUN_ERR_RESOLVE;

-	goto on_error;

-    }

-

-    /* Init mapped addresses to zero */

-    pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in));

-

-    /* Main retransmission loop. */

-    for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {

-	pj_time_val next_tx, now;

-	pj_fd_set_t r;

-	int select_rc;

-

-	PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d", 

-			     send_cnt, wait_resp));

-

-	PJ_FD_ZERO(&r);

-

-	/* Send messages to servers that has not given us response. */

-	for (i=0; i<sock_cnt && mapped_status==0; ++i) {

-	    for (j=0; j<2 && mapped_status==0; ++j) {

-		pj_stun_msg_hdr *msg_hdr = out_msg;

-                pj_ssize_t sent_len;

-

-		if (rec[i].srv[j].mapped_port != 0)

-		    continue;

-

-		/* Modify message so that we can distinguish response. */

-		msg_hdr->tsx[2] = pj_htonl(i);

-		msg_hdr->tsx[3] = pj_htonl(j);

-

-		/* Send! */

-                sent_len = out_msg_len;

-		rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,

-				    (pj_sockaddr_t*)&srv_addr[j], 

-				    sizeof(pj_sockaddr_in));

-		if (sent_len != (int)out_msg_len) {

-		    PJ_LOG(4,(THIS_FILE, 

-			      "Error sending STUN request to %s:%d",

-			      LOG_ADDR(srv_addr[j])));

-		    mapped_status = PJ_STUN_ERR_TRANSPORT; 

-		} else {

-		    ++wait_resp;

-		}

-	    }

-	}

-

-	/* All requests sent.

-	 * The loop below will wait for responses until all responses have

-	 * been received (i.e. wait_resp==0) or timeout occurs, which then

-	 * we'll go to the next retransmission iteration.

-	 */

-

-	/* Calculate time of next retransmission. */

-	pj_gettimeofday(&next_tx);

-	next_tx.sec += (stun_timer[send_cnt]/1000);

-	next_tx.msec += (stun_timer[send_cnt]%1000);

-	pj_time_val_normalize(&next_tx);

-

-	for (pj_gettimeofday(&now), select_rc=1; 

-	     mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); 

-	     pj_gettimeofday(&now)) 

-	{

-	    pj_time_val timeout;

-

-	    timeout = next_tx;

-	    PJ_TIME_VAL_SUB(timeout, now);

-

-	    for (i=0; i<sock_cnt; ++i) {

-		PJ_FD_SET(sock[i], &r);

-	    }

-

-	    select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout);

-	    if (select_rc < 1)

-		continue;

-

-	    for (i=0; i<sock_cnt; ++i) {

-		int sock_idx, srv_idx;

-                pj_ssize_t len;

-		pj_stun_msg msg;

-		pj_sockaddr_in addr;

-		int addrlen = sizeof(addr);

-		pj_stun_mapped_addr_attr *attr;

-		char recv_buf[128];

-

-		if (!PJ_FD_ISSET(sock[i], &r))

-		    continue;

-

-                len = sizeof(recv_buf);

-		pj_sock_recvfrom( sock[i], recv_buf, 

-				  &len, 0,

-				  (pj_sockaddr_t*)&addr,

-				  &addrlen);

-

-		--wait_resp;

-

-		if (len < 1) {

-		    mapped_status = PJ_STUN_ERR_TRANSPORT; 

-		    continue;

-		}

-

-		if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) {

-		    PJ_LOG(4,(THIS_FILE, 

-				"Error parsing STUN response from %s:%d",

-				LOG_ADDR(addr)));

-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

-		    continue;

-		}

-

-		sock_idx = pj_ntohl(msg.hdr->tsx[2]);

-		srv_idx = pj_ntohl(msg.hdr->tsx[3]);

-

-		if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) {

-		    PJ_LOG(4,(THIS_FILE, 

-				"Invalid transaction ID from %s:%d", 

-				LOG_ADDR(addr)));

-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

-		    continue;

-		}

-

-		if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) {

-		    PJ_LOG(4,(THIS_FILE, 

-				"Non binding response %d from %s:%d", 

-				pj_ntohs(msg.hdr->type), LOG_ADDR(addr)));

-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

-		    continue;

-		}

-

-		if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) {

-		    PJ_LOG(4,(THIS_FILE, 

-				"Got STUN error attribute from %s:%d",

-				LOG_ADDR(addr)));

-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

-		    continue;

-		}

-

-		attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR);

-		if (!attr) {

-		    PJ_LOG(4,(THIS_FILE,

-				"No mapped address in response from %s:%d",

-				LOG_ADDR(addr)));

-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

-		    continue;

-		}

-

-		rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr;

-		rec[sock_idx].srv[srv_idx].mapped_port = attr->port;

-	    }

-	}

-

-	/* The best scenario is if all requests have been replied.

-	 * Then we don't need to go to the next retransmission iteration.

-	 */

-	if (wait_resp <= 0)

-	    break;

-    }

-

-    for (i=0; i<sock_cnt && mapped_status==0; ++i) {

-	if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr &&

-	    rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port)

-	{

-	    mapped_addr[i].sin_family = PJ_AF_INET;

-	    mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr;

-	    mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port;

-

-	    if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) {

-		mapped_status = PJ_STUN_ERR_NO_RESPONSE;

-	    }

-	} else {

-	    mapped_status = PJ_STUN_ERR_SYMETRIC;

-	}

-    }

-

-    pj_pool_release(pool);

-

-    return mapped_status;

-

-on_error:

-    if (pool) pj_pool_release(pool);

-    return -1;

-}

-

-PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status)

-{

-    switch (status) {

-    case 0:			    return "No error";

-    case -1:			    return "General error";

-    case PJ_STUN_ERR_MEMORY:	    return "Memory allocation failed";

-    case PJ_STUN_ERR_RESOLVE:	    return "Invalid IP or unable to resolve STUN server";

-    case PJ_STUN_ERR_TRANSPORT:	    return "Unable to contact STUN server";

-    case PJ_STUN_ERR_INVALID_MSG:   return "Invalid response from STUN server";

-    case PJ_STUN_ERR_NO_RESPONSE:   return "No response from STUN server";

-    case PJ_STUN_ERR_SYMETRIC:	    return "Different mappings are returned from servers";

-    }

-    return "Unknown error";

-}

+/* $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 <pjlib-util/stun.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/os.h>
+#include <pj/sock_select.h>
+
+enum { MAX_REQUEST = 3 };
+static int stun_timer[] = {1600, 1600, 1600 };
+
+#define THIS_FILE	"stunclient"
+#define LOG_ADDR(addr)	pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port)
+
+
+PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,
+					      int sock_cnt, pj_sock_t sock[],
+					      const pj_str_t *srv1, int port1,
+					      const pj_str_t *srv2, int port2,
+					      pj_sockaddr_in mapped_addr[])
+{
+    pj_sockaddr_in srv_addr[2];
+    int i, j, rc, send_cnt = 0;
+    pj_pool_t *pool;
+    struct {
+	struct {
+	    pj_uint32_t	mapped_addr;
+	    pj_uint32_t	mapped_port;
+	} srv[2];
+    } *rec;
+    void       *out_msg;
+    pj_size_t	out_msg_len;
+    int wait_resp = 0;
+    int mapped_status = 0;
+
+    PJ_CHECK_STACK();
+
+    /* Create pool. */
+    pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL);
+    if (!pool) {
+	mapped_status = PJ_STUN_ERR_MEMORY; 
+	return -1;
+    }
+
+    /* Allocate client records */
+    rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec));
+    if (!rec) {
+	mapped_status = PJ_STUN_ERR_MEMORY; 
+	goto on_error;
+    }
+
+    /* Create the outgoing BIND REQUEST message template */
+    rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0);
+    if (rc != 0) {
+	mapped_status = -1;
+	goto on_error;
+    }
+
+    /* Resolve servers. */
+    if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) {
+	mapped_status = PJ_STUN_ERR_RESOLVE; 
+	goto on_error;
+    }
+    if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) {
+	mapped_status = PJ_STUN_ERR_RESOLVE;
+	goto on_error;
+    }
+
+    /* Init mapped addresses to zero */
+    pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in));
+
+    /* Main retransmission loop. */
+    for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {
+	pj_time_val next_tx, now;
+	pj_fd_set_t r;
+	int select_rc;
+
+	PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d", 
+			     send_cnt, wait_resp));
+
+	PJ_FD_ZERO(&r);
+
+	/* Send messages to servers that has not given us response. */
+	for (i=0; i<sock_cnt && mapped_status==0; ++i) {
+	    for (j=0; j<2 && mapped_status==0; ++j) {
+		pj_stun_msg_hdr *msg_hdr = out_msg;
+                pj_ssize_t sent_len;
+
+		if (rec[i].srv[j].mapped_port != 0)
+		    continue;
+
+		/* Modify message so that we can distinguish response. */
+		msg_hdr->tsx[2] = pj_htonl(i);
+		msg_hdr->tsx[3] = pj_htonl(j);
+
+		/* Send! */
+                sent_len = out_msg_len;
+		rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,
+				    (pj_sockaddr_t*)&srv_addr[j], 
+				    sizeof(pj_sockaddr_in));
+		if (sent_len != (int)out_msg_len) {
+		    PJ_LOG(4,(THIS_FILE, 
+			      "Error sending STUN request to %s:%d",
+			      LOG_ADDR(srv_addr[j])));
+		    mapped_status = PJ_STUN_ERR_TRANSPORT; 
+		} else {
+		    ++wait_resp;
+		}
+	    }
+	}
+
+	/* All requests sent.
+	 * The loop below will wait for responses until all responses have
+	 * been received (i.e. wait_resp==0) or timeout occurs, which then
+	 * we'll go to the next retransmission iteration.
+	 */
+
+	/* Calculate time of next retransmission. */
+	pj_gettimeofday(&next_tx);
+	next_tx.sec += (stun_timer[send_cnt]/1000);
+	next_tx.msec += (stun_timer[send_cnt]%1000);
+	pj_time_val_normalize(&next_tx);
+
+	for (pj_gettimeofday(&now), select_rc=1; 
+	     mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); 
+	     pj_gettimeofday(&now)) 
+	{
+	    pj_time_val timeout;
+
+	    timeout = next_tx;
+	    PJ_TIME_VAL_SUB(timeout, now);
+
+	    for (i=0; i<sock_cnt; ++i) {
+		PJ_FD_SET(sock[i], &r);
+	    }
+
+	    select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout);
+	    if (select_rc < 1)
+		continue;
+
+	    for (i=0; i<sock_cnt; ++i) {
+		int sock_idx, srv_idx;
+                pj_ssize_t len;
+		pj_stun_msg msg;
+		pj_sockaddr_in addr;
+		int addrlen = sizeof(addr);
+		pj_stun_mapped_addr_attr *attr;
+		char recv_buf[128];
+
+		if (!PJ_FD_ISSET(sock[i], &r))
+		    continue;
+
+                len = sizeof(recv_buf);
+		pj_sock_recvfrom( sock[i], recv_buf, 
+				  &len, 0,
+				  (pj_sockaddr_t*)&addr,
+				  &addrlen);
+
+		--wait_resp;
+
+		if (len < 1) {
+		    mapped_status = PJ_STUN_ERR_TRANSPORT; 
+		    continue;
+		}
+
+		if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) {
+		    PJ_LOG(4,(THIS_FILE, 
+				"Error parsing STUN response from %s:%d",
+				LOG_ADDR(addr)));
+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
+		    continue;
+		}
+
+		sock_idx = pj_ntohl(msg.hdr->tsx[2]);
+		srv_idx = pj_ntohl(msg.hdr->tsx[3]);
+
+		if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) {
+		    PJ_LOG(4,(THIS_FILE, 
+				"Invalid transaction ID from %s:%d", 
+				LOG_ADDR(addr)));
+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
+		    continue;
+		}
+
+		if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) {
+		    PJ_LOG(4,(THIS_FILE, 
+				"Non binding response %d from %s:%d", 
+				pj_ntohs(msg.hdr->type), LOG_ADDR(addr)));
+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
+		    continue;
+		}
+
+		if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) {
+		    PJ_LOG(4,(THIS_FILE, 
+				"Got STUN error attribute from %s:%d",
+				LOG_ADDR(addr)));
+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
+		    continue;
+		}
+
+		attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR);
+		if (!attr) {
+		    PJ_LOG(4,(THIS_FILE,
+				"No mapped address in response from %s:%d",
+				LOG_ADDR(addr)));
+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
+		    continue;
+		}
+
+		rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr;
+		rec[sock_idx].srv[srv_idx].mapped_port = attr->port;
+	    }
+	}
+
+	/* The best scenario is if all requests have been replied.
+	 * Then we don't need to go to the next retransmission iteration.
+	 */
+	if (wait_resp <= 0)
+	    break;
+    }
+
+    for (i=0; i<sock_cnt && mapped_status==0; ++i) {
+	if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr &&
+	    rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port)
+	{
+	    mapped_addr[i].sin_family = PJ_AF_INET;
+	    mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr;
+	    mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port;
+
+	    if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) {
+		mapped_status = PJ_STUN_ERR_NO_RESPONSE;
+	    }
+	} else {
+	    mapped_status = PJ_STUN_ERR_SYMETRIC;
+	}
+    }
+
+    pj_pool_release(pool);
+
+    return mapped_status;
+
+on_error:
+    if (pool) pj_pool_release(pool);
+    return -1;
+}
+
+PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status)
+{
+    switch (status) {
+    case 0:			    return "No error";
+    case -1:			    return "General error";
+    case PJ_STUN_ERR_MEMORY:	    return "Memory allocation failed";
+    case PJ_STUN_ERR_RESOLVE:	    return "Invalid IP or unable to resolve STUN server";
+    case PJ_STUN_ERR_TRANSPORT:	    return "Unable to contact STUN server";
+    case PJ_STUN_ERR_INVALID_MSG:   return "Invalid response from STUN server";
+    case PJ_STUN_ERR_NO_RESPONSE:   return "No response from STUN server";
+    case PJ_STUN_ERR_SYMETRIC:	    return "Different mappings are returned from servers";
+    }
+    return "Unknown error";
+}
diff --git a/pjlib-util/src/pjlib-util/symbols.c b/pjlib-util/src/pjlib-util/symbols.c
index 123d401..00558a0 100644
--- a/pjlib-util/src/pjlib-util/symbols.c
+++ b/pjlib-util/src/pjlib-util/symbols.c
@@ -1,82 +1,82 @@
-/* $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 <pjlib.h>

-#include <pjlib-util.h>

-

-/*

- * md5.h

- */

-PJ_EXPORT_SYMBOL(md5_init)

-PJ_EXPORT_SYMBOL(md5_append)

-PJ_EXPORT_SYMBOL(md5_finish)

-

-/*

- * scanner.h

- */

-PJ_EXPORT_SYMBOL(pj_cs_init)

-PJ_EXPORT_SYMBOL(pj_cs_set)

-PJ_EXPORT_SYMBOL(pj_cs_add_range)

-PJ_EXPORT_SYMBOL(pj_cs_add_alpha)

-PJ_EXPORT_SYMBOL(pj_cs_add_num)

-PJ_EXPORT_SYMBOL(pj_cs_add_str)

-PJ_EXPORT_SYMBOL(pj_cs_del_range)

-PJ_EXPORT_SYMBOL(pj_cs_del_str)

-PJ_EXPORT_SYMBOL(pj_cs_invert)

-PJ_EXPORT_SYMBOL(pj_scan_init)

-PJ_EXPORT_SYMBOL(pj_scan_fini)

-PJ_EXPORT_SYMBOL(pj_scan_peek)

-PJ_EXPORT_SYMBOL(pj_scan_peek_n)

-PJ_EXPORT_SYMBOL(pj_scan_peek_until)

-PJ_EXPORT_SYMBOL(pj_scan_get)

-PJ_EXPORT_SYMBOL(pj_scan_get_quote)

-PJ_EXPORT_SYMBOL(pj_scan_get_n)

-PJ_EXPORT_SYMBOL(pj_scan_get_char)

-PJ_EXPORT_SYMBOL(pj_scan_get_newline)

-PJ_EXPORT_SYMBOL(pj_scan_get_until)

-PJ_EXPORT_SYMBOL(pj_scan_get_until_ch)

-PJ_EXPORT_SYMBOL(pj_scan_get_until_chr)

-PJ_EXPORT_SYMBOL(pj_scan_advance_n)

-PJ_EXPORT_SYMBOL(pj_scan_strcmp)

-PJ_EXPORT_SYMBOL(pj_scan_stricmp)

-PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace)

-PJ_EXPORT_SYMBOL(pj_scan_save_state)

-PJ_EXPORT_SYMBOL(pj_scan_restore_state)

-

-/*

- * stun.h

- */

-PJ_EXPORT_SYMBOL(pj_stun_create_bind_req)

-PJ_EXPORT_SYMBOL(pj_stun_parse_msg)

-PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr)

-PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr)

-PJ_EXPORT_SYMBOL(pj_stun_get_err_msg)

-

-/*

- * xml.h

- */

-PJ_EXPORT_SYMBOL(pj_xml_parse)

-PJ_EXPORT_SYMBOL(pj_xml_print)

-PJ_EXPORT_SYMBOL(pj_xml_add_node)

-PJ_EXPORT_SYMBOL(pj_xml_add_attr)

-PJ_EXPORT_SYMBOL(pj_xml_find_node)

-PJ_EXPORT_SYMBOL(pj_xml_find_next_node)

-PJ_EXPORT_SYMBOL(pj_xml_find_attr)

-PJ_EXPORT_SYMBOL(pj_xml_find)

-

-

+/* $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 <pjlib.h>
+#include <pjlib-util.h>
+
+/*
+ * md5.h
+ */
+PJ_EXPORT_SYMBOL(md5_init)
+PJ_EXPORT_SYMBOL(md5_append)
+PJ_EXPORT_SYMBOL(md5_finish)
+
+/*
+ * scanner.h
+ */
+PJ_EXPORT_SYMBOL(pj_cs_init)
+PJ_EXPORT_SYMBOL(pj_cs_set)
+PJ_EXPORT_SYMBOL(pj_cs_add_range)
+PJ_EXPORT_SYMBOL(pj_cs_add_alpha)
+PJ_EXPORT_SYMBOL(pj_cs_add_num)
+PJ_EXPORT_SYMBOL(pj_cs_add_str)
+PJ_EXPORT_SYMBOL(pj_cs_del_range)
+PJ_EXPORT_SYMBOL(pj_cs_del_str)
+PJ_EXPORT_SYMBOL(pj_cs_invert)
+PJ_EXPORT_SYMBOL(pj_scan_init)
+PJ_EXPORT_SYMBOL(pj_scan_fini)
+PJ_EXPORT_SYMBOL(pj_scan_peek)
+PJ_EXPORT_SYMBOL(pj_scan_peek_n)
+PJ_EXPORT_SYMBOL(pj_scan_peek_until)
+PJ_EXPORT_SYMBOL(pj_scan_get)
+PJ_EXPORT_SYMBOL(pj_scan_get_quote)
+PJ_EXPORT_SYMBOL(pj_scan_get_n)
+PJ_EXPORT_SYMBOL(pj_scan_get_char)
+PJ_EXPORT_SYMBOL(pj_scan_get_newline)
+PJ_EXPORT_SYMBOL(pj_scan_get_until)
+PJ_EXPORT_SYMBOL(pj_scan_get_until_ch)
+PJ_EXPORT_SYMBOL(pj_scan_get_until_chr)
+PJ_EXPORT_SYMBOL(pj_scan_advance_n)
+PJ_EXPORT_SYMBOL(pj_scan_strcmp)
+PJ_EXPORT_SYMBOL(pj_scan_stricmp)
+PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace)
+PJ_EXPORT_SYMBOL(pj_scan_save_state)
+PJ_EXPORT_SYMBOL(pj_scan_restore_state)
+
+/*
+ * stun.h
+ */
+PJ_EXPORT_SYMBOL(pj_stun_create_bind_req)
+PJ_EXPORT_SYMBOL(pj_stun_parse_msg)
+PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr)
+PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr)
+PJ_EXPORT_SYMBOL(pj_stun_get_err_msg)
+
+/*
+ * xml.h
+ */
+PJ_EXPORT_SYMBOL(pj_xml_parse)
+PJ_EXPORT_SYMBOL(pj_xml_print)
+PJ_EXPORT_SYMBOL(pj_xml_add_node)
+PJ_EXPORT_SYMBOL(pj_xml_add_attr)
+PJ_EXPORT_SYMBOL(pj_xml_find_node)
+PJ_EXPORT_SYMBOL(pj_xml_find_next_node)
+PJ_EXPORT_SYMBOL(pj_xml_find_attr)
+PJ_EXPORT_SYMBOL(pj_xml_find)
+
+
diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c
index 3be7bee..140c64c 100644
--- a/pjlib-util/src/pjlib-util/xml.c
+++ b/pjlib-util/src/pjlib-util/xml.c
@@ -1,396 +1,396 @@
-/* $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 <pjlib-util/xml.h>

-#include <pjlib-util/scanner.h>

-#include <pj/except.h>

-#include <pj/pool.h>

-#include <pj/string.h>

-#include <pj/log.h>

-#include <pj/os.h>

-

-#define EX_SYNTAX_ERROR	12

-#define THIS_FILE	"xml.c"

-

-static void on_syntax_error(struct pj_scanner *scanner)

-{

-    PJ_UNUSED_ARG(scanner);

-    PJ_THROW(EX_SYNTAX_ERROR);

-}

-

-static pj_xml_node *alloc_node( pj_pool_t *pool )

-{

-    pj_xml_node *node;

-

-    node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node));

-    pj_list_init( &node->attr_head );

-    pj_list_init( &node->node_head );

-

-    return node;

-}

-

-static pj_xml_attr *alloc_attr( pj_pool_t *pool )

-{

-    return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr));

-}

-

-/* This is a recursive function! */

-static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)

-{

-    pj_xml_node *node;

-    pj_str_t end_name;

-

-    PJ_CHECK_STACK();

-

-    if (*scanner->curptr != '<')

-	on_syntax_error(scanner);

-

-    /* Handle Processing Instructino (PI) construct (i.e. "<?") */

-    if (*scanner->curptr == '<' && *(scanner->curptr+1) == '?') {

-	pj_scan_advance_n(scanner, 2, PJ_FALSE);

-	for (;;) {

-	    pj_str_t dummy;

-	    pj_scan_get_until_ch(scanner, '?', &dummy);

-	    if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') {

-		pj_scan_advance_n(scanner, 2, PJ_TRUE);

-		break;

-	    } else {

-		pj_scan_advance_n(scanner, 1, PJ_FALSE);

-	    }

-	}

-	return xml_parse_node(pool, scanner);

-    }

-

-    /* Handle comments construct (i.e. "<!--") */

-    if (pj_scan_strcmp(scanner, "<!--", 4) == 0) {

-	pj_scan_advance_n(scanner, 4, PJ_FALSE);

-	for (;;) {

-	    pj_str_t dummy;

-	    pj_scan_get_until_ch(scanner, '-', &dummy);

-	    if (pj_scan_strcmp(scanner, "-->", 3) == 0) {

-		pj_scan_advance_n(scanner, 3, PJ_TRUE);

-		break;

-	    } else {

-		pj_scan_advance_n(scanner, 1, PJ_FALSE);

-	    }

-	}

-	return xml_parse_node(pool, scanner);

-    }

-

-    /* Alloc node. */

-    node = alloc_node(pool);

-

-    /* Get '<' */

-    pj_scan_get_char(scanner);

-

-    /* Get node name. */

-    pj_scan_get_until_chr( scanner, " />\t", &node->name);

-

-    /* Get attributes. */

-    while (*scanner->curptr != '>' && *scanner->curptr != '/') {

-	pj_xml_attr *attr = alloc_attr(pool);

-	

-	pj_scan_get_until_chr( scanner, "=> \t", &attr->name);

-	if (*scanner->curptr == '=') {

-	    pj_scan_get_char( scanner );

-	    pj_scan_get_quote(scanner, '"', '"', &attr->value);

-	    /* remove quote characters */

-	    ++attr->value.ptr;

-	    attr->value.slen -= 2;

-	}

-	

-	pj_list_insert_before( &node->attr_head, attr );

-    }

-

-    if (*scanner->curptr == '/') {

-	pj_scan_get_char(scanner);

-	if (pj_scan_get_char(scanner) != '>')

-	    on_syntax_error(scanner);

-	return node;

-    }

-

-    /* Enclosing bracket. */

-    if (pj_scan_get_char(scanner) != '>')

-	on_syntax_error(scanner);

-

-    /* Sub nodes. */

-    while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') {

-	pj_xml_node *sub_node = xml_parse_node(pool, scanner);

-	pj_list_insert_before( &node->node_head, sub_node );

-    }

-

-    /* Content. */

-    if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') {

-	pj_scan_get_until_ch(scanner, '<', &node->content);

-    }

-

-    /* Enclosing node. */

-    if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/')

-	on_syntax_error(scanner);

-

-    pj_scan_get_until_chr(scanner, " \t>", &end_name);

-

-    /* Compare name. */

-    if (pj_stricmp(&node->name, &end_name) != 0)

-	on_syntax_error(scanner);

-

-    /* Enclosing '>' */

-    if (pj_scan_get_char(scanner) != '>')

-	on_syntax_error(scanner);

-

-    return node;

-}

-

-PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len)

-{

-    pj_xml_node *node = NULL;

-    pj_scanner scanner;

-    PJ_USE_EXCEPTION;

-

-    if (!msg || !len || !pool)

-	return NULL;

-

-    pj_scan_init( &scanner, msg, len, 

-		  PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, 

-		  &on_syntax_error);

-    PJ_TRY {

-	node =  xml_parse_node(pool, &scanner);

-    }

-    PJ_DEFAULT {

-	PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d",

-		  scanner.line, scanner.col));

-    }

-    PJ_END;

-    pj_scan_fini( &scanner );

-    return node;

-}

-

-/* This is a recursive function. */

-static int xml_print_node( const pj_xml_node *node, int indent, 

-			   char *buf, pj_size_t len )

-{

-    int i;

-    char *p = buf;

-    pj_xml_attr *attr;

-    pj_xml_node *sub_node;

-

-#define SIZE_LEFT()	((int)(len - (p-buf)))

-

-    PJ_CHECK_STACK();

-

-    /* Print name. */

-    if (SIZE_LEFT() < node->name.slen + indent + 5)

-	return -1;

-    for (i=0; i<indent; ++i)

-	*p++ = ' ';

-    *p++ = '<';

-    pj_memcpy(p, node->name.ptr, node->name.slen);

-    p += node->name.slen;

-

-    /* Print attributes. */

-    attr = node->attr_head.next;

-    while (attr != &node->attr_head) {

-

-	if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4)

-	    return -1;

-

-	*p++ = ' ';

-

-	/* Attribute name. */

-	pj_memcpy(p, attr->name.ptr, attr->name.slen);

-	p += attr->name.slen;

-

-	/* Attribute value. */

-	if (attr->value.slen) {

-	    *p++ = '=';

-	    *p++ = '"';

-	    pj_memcpy(p, attr->value.ptr, attr->value.slen);

-	    p += attr->value.slen;

-	    *p++ = '"';

-	}

-

-	attr = attr->next;

-    }

-

-    /* Check for empty node. */

-    if (node->content.slen==0 &&

-	node->node_head.next==(pj_xml_node*)&node->node_head)

-    {

-	*p++ = ' ';

-	*p++ = '/';

-	*p++ = '>';

-	return p-buf;

-    }

-

-    /* Enclosing '>' */

-    if (SIZE_LEFT() < 1) return -1;

-    *p++ = '>';

-

-    /* Print sub nodes. */

-    sub_node = node->node_head.next;

-    while (sub_node != (pj_xml_node*)&node->node_head) {

-	int printed;

-

-	if (SIZE_LEFT() < indent + 3)

-	    return -1;

-	//*p++ = '\r';

-	*p++ = '\n';

-

-	printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT());

-	if (printed < 0)

-	    return -1;

-

-	p += printed;

-	sub_node = sub_node->next;

-    }

-

-    /* Content. */

-    if (node->content.slen) {

-	if (SIZE_LEFT() < node->content.slen) return -1;

-	pj_memcpy(p, node->content.ptr, node->content.slen);

-	p += node->content.slen;

-    }

-

-    /* Enclosing node. */

-    if (node->node_head.next != (pj_xml_node*)&node->node_head) {

-	if (SIZE_LEFT() < node->name.slen + 5 + indent)

-	    return -1;

-	//*p++ = '\r';

-	*p++ = '\n';

-	for (i=0; i<indent; ++i)

-	    *p++ = ' ';

-    } else {

-	if (SIZE_LEFT() < node->name.slen + 3)

-	    return -1;

-    }

-    *p++ = '<';

-    *p++ = '/';

-    pj_memcpy(p, node->name.ptr, node->name.slen);

-    p += node->name.slen;

-    *p++ = '>';

-

-#undef SIZE_LEFT

-

-    return p - buf;

-}

-

-PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len,

-			 pj_bool_t include_prolog)

-{

-    int prolog_len = 0;

-    int printed;

-

-    if (!node || !buf || !len)

-	return 0;

-

-    if (include_prolog) {

-	pj_str_t prolog = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39};

-	if ((int)len < prolog.slen)

-	    return -1;

-	pj_memcpy(buf, prolog.ptr, prolog.slen);

-	prolog_len = prolog.slen;

-    }

-

-    printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len;

-    if (printed > 0 && len-printed >= 1) {

-	buf[printed++] = '\n';

-    }

-    return printed;

-}

-

-

-PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node )

-{

-    pj_list_insert_before(&parent->node_head, node);

-}

-

-PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr )

-{

-    pj_list_insert_before(&node->attr_head, attr);

-}

-

-PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name)

-{

-    pj_xml_node *node = parent->node_head.next;

-

-    PJ_CHECK_STACK();

-

-    while (node != (void*)&parent->node_head) {

-	if (pj_stricmp(&node->name, name) == 0)

-	    return node;

-	node = node->next;

-    }

-    return NULL;

-}

-

-

-PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node,

-					    const pj_str_t *name)

-{

-    PJ_CHECK_STACK();

-

-    node = node->next;

-    while (node != (void*)&parent->node_head) {

-	if (pj_stricmp(&node->name, name) == 0)

-	    return node;

-	node = node->next;

-    }

-    return NULL;

-}

-

-

-PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name,

-				       const pj_str_t *value)

-{

-    pj_xml_attr *attr = node->attr_head.next;

-    while (attr != (void*)&node->attr_head) {

-	if (pj_stricmp(&attr->name, name)==0) {

-	    if (value) {

-		if (pj_stricmp(&attr->value, value)==0)

-		    return attr;

-	    } else {

-		return attr;

-	    }

-	}

-	attr = attr->next;

-    }

-    return NULL;

-}

-

-

-

-PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,

-				  const void *data, 

-				  pj_bool_t (*match)(pj_xml_node *, const void*))

-{

-    pj_xml_node *head = (void*)&parent->node_head, *node = head->next;

-

-    while (node != (void*)head) {

-	if (name && pj_stricmp(&node->name, name)==0) {

-	    if (match) {

-		if (match(node, data))

-		    return node;

-	    } else {

-		return node;

-	    }

-	}

-	node = node->next;

-    }

-    return NULL;

-}

-

+/* $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 <pjlib-util/xml.h>
+#include <pjlib-util/scanner.h>
+#include <pj/except.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/log.h>
+#include <pj/os.h>
+
+#define EX_SYNTAX_ERROR	12
+#define THIS_FILE	"xml.c"
+
+static void on_syntax_error(struct pj_scanner *scanner)
+{
+    PJ_UNUSED_ARG(scanner);
+    PJ_THROW(EX_SYNTAX_ERROR);
+}
+
+static pj_xml_node *alloc_node( pj_pool_t *pool )
+{
+    pj_xml_node *node;
+
+    node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node));
+    pj_list_init( &node->attr_head );
+    pj_list_init( &node->node_head );
+
+    return node;
+}
+
+static pj_xml_attr *alloc_attr( pj_pool_t *pool )
+{
+    return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr));
+}
+
+/* This is a recursive function! */
+static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)
+{
+    pj_xml_node *node;
+    pj_str_t end_name;
+
+    PJ_CHECK_STACK();
+
+    if (*scanner->curptr != '<')
+	on_syntax_error(scanner);
+
+    /* Handle Processing Instructino (PI) construct (i.e. "<?") */
+    if (*scanner->curptr == '<' && *(scanner->curptr+1) == '?') {
+	pj_scan_advance_n(scanner, 2, PJ_FALSE);
+	for (;;) {
+	    pj_str_t dummy;
+	    pj_scan_get_until_ch(scanner, '?', &dummy);
+	    if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') {
+		pj_scan_advance_n(scanner, 2, PJ_TRUE);
+		break;
+	    } else {
+		pj_scan_advance_n(scanner, 1, PJ_FALSE);
+	    }
+	}
+	return xml_parse_node(pool, scanner);
+    }
+
+    /* Handle comments construct (i.e. "<!--") */
+    if (pj_scan_strcmp(scanner, "<!--", 4) == 0) {
+	pj_scan_advance_n(scanner, 4, PJ_FALSE);
+	for (;;) {
+	    pj_str_t dummy;
+	    pj_scan_get_until_ch(scanner, '-', &dummy);
+	    if (pj_scan_strcmp(scanner, "-->", 3) == 0) {
+		pj_scan_advance_n(scanner, 3, PJ_TRUE);
+		break;
+	    } else {
+		pj_scan_advance_n(scanner, 1, PJ_FALSE);
+	    }
+	}
+	return xml_parse_node(pool, scanner);
+    }
+
+    /* Alloc node. */
+    node = alloc_node(pool);
+
+    /* Get '<' */
+    pj_scan_get_char(scanner);
+
+    /* Get node name. */
+    pj_scan_get_until_chr( scanner, " />\t", &node->name);
+
+    /* Get attributes. */
+    while (*scanner->curptr != '>' && *scanner->curptr != '/') {
+	pj_xml_attr *attr = alloc_attr(pool);
+	
+	pj_scan_get_until_chr( scanner, "=> \t", &attr->name);
+	if (*scanner->curptr == '=') {
+	    pj_scan_get_char( scanner );
+	    pj_scan_get_quote(scanner, '"', '"', &attr->value);
+	    /* remove quote characters */
+	    ++attr->value.ptr;
+	    attr->value.slen -= 2;
+	}
+	
+	pj_list_insert_before( &node->attr_head, attr );
+    }
+
+    if (*scanner->curptr == '/') {
+	pj_scan_get_char(scanner);
+	if (pj_scan_get_char(scanner) != '>')
+	    on_syntax_error(scanner);
+	return node;
+    }
+
+    /* Enclosing bracket. */
+    if (pj_scan_get_char(scanner) != '>')
+	on_syntax_error(scanner);
+
+    /* Sub nodes. */
+    while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') {
+	pj_xml_node *sub_node = xml_parse_node(pool, scanner);
+	pj_list_insert_before( &node->node_head, sub_node );
+    }
+
+    /* Content. */
+    if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') {
+	pj_scan_get_until_ch(scanner, '<', &node->content);
+    }
+
+    /* Enclosing node. */
+    if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/')
+	on_syntax_error(scanner);
+
+    pj_scan_get_until_chr(scanner, " \t>", &end_name);
+
+    /* Compare name. */
+    if (pj_stricmp(&node->name, &end_name) != 0)
+	on_syntax_error(scanner);
+
+    /* Enclosing '>' */
+    if (pj_scan_get_char(scanner) != '>')
+	on_syntax_error(scanner);
+
+    return node;
+}
+
+PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len)
+{
+    pj_xml_node *node = NULL;
+    pj_scanner scanner;
+    PJ_USE_EXCEPTION;
+
+    if (!msg || !len || !pool)
+	return NULL;
+
+    pj_scan_init( &scanner, msg, len, 
+		  PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, 
+		  &on_syntax_error);
+    PJ_TRY {
+	node =  xml_parse_node(pool, &scanner);
+    }
+    PJ_DEFAULT {
+	PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d",
+		  scanner.line, scanner.col));
+    }
+    PJ_END;
+    pj_scan_fini( &scanner );
+    return node;
+}
+
+/* This is a recursive function. */
+static int xml_print_node( const pj_xml_node *node, int indent, 
+			   char *buf, pj_size_t len )
+{
+    int i;
+    char *p = buf;
+    pj_xml_attr *attr;
+    pj_xml_node *sub_node;
+
+#define SIZE_LEFT()	((int)(len - (p-buf)))
+
+    PJ_CHECK_STACK();
+
+    /* Print name. */
+    if (SIZE_LEFT() < node->name.slen + indent + 5)
+	return -1;
+    for (i=0; i<indent; ++i)
+	*p++ = ' ';
+    *p++ = '<';
+    pj_memcpy(p, node->name.ptr, node->name.slen);
+    p += node->name.slen;
+
+    /* Print attributes. */
+    attr = node->attr_head.next;
+    while (attr != &node->attr_head) {
+
+	if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4)
+	    return -1;
+
+	*p++ = ' ';
+
+	/* Attribute name. */
+	pj_memcpy(p, attr->name.ptr, attr->name.slen);
+	p += attr->name.slen;
+
+	/* Attribute value. */
+	if (attr->value.slen) {
+	    *p++ = '=';
+	    *p++ = '"';
+	    pj_memcpy(p, attr->value.ptr, attr->value.slen);
+	    p += attr->value.slen;
+	    *p++ = '"';
+	}
+
+	attr = attr->next;
+    }
+
+    /* Check for empty node. */
+    if (node->content.slen==0 &&
+	node->node_head.next==(pj_xml_node*)&node->node_head)
+    {
+	*p++ = ' ';
+	*p++ = '/';
+	*p++ = '>';
+	return p-buf;
+    }
+
+    /* Enclosing '>' */
+    if (SIZE_LEFT() < 1) return -1;
+    *p++ = '>';
+
+    /* Print sub nodes. */
+    sub_node = node->node_head.next;
+    while (sub_node != (pj_xml_node*)&node->node_head) {
+	int printed;
+
+	if (SIZE_LEFT() < indent + 3)
+	    return -1;
+	//*p++ = '\r';
+	*p++ = '\n';
+
+	printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT());
+	if (printed < 0)
+	    return -1;
+
+	p += printed;
+	sub_node = sub_node->next;
+    }
+
+    /* Content. */
+    if (node->content.slen) {
+	if (SIZE_LEFT() < node->content.slen) return -1;
+	pj_memcpy(p, node->content.ptr, node->content.slen);
+	p += node->content.slen;
+    }
+
+    /* Enclosing node. */
+    if (node->node_head.next != (pj_xml_node*)&node->node_head) {
+	if (SIZE_LEFT() < node->name.slen + 5 + indent)
+	    return -1;
+	//*p++ = '\r';
+	*p++ = '\n';
+	for (i=0; i<indent; ++i)
+	    *p++ = ' ';
+    } else {
+	if (SIZE_LEFT() < node->name.slen + 3)
+	    return -1;
+    }
+    *p++ = '<';
+    *p++ = '/';
+    pj_memcpy(p, node->name.ptr, node->name.slen);
+    p += node->name.slen;
+    *p++ = '>';
+
+#undef SIZE_LEFT
+
+    return p - buf;
+}
+
+PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len,
+			 pj_bool_t include_prolog)
+{
+    int prolog_len = 0;
+    int printed;
+
+    if (!node || !buf || !len)
+	return 0;
+
+    if (include_prolog) {
+	pj_str_t prolog = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39};
+	if ((int)len < prolog.slen)
+	    return -1;
+	pj_memcpy(buf, prolog.ptr, prolog.slen);
+	prolog_len = prolog.slen;
+    }
+
+    printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len;
+    if (printed > 0 && len-printed >= 1) {
+	buf[printed++] = '\n';
+    }
+    return printed;
+}
+
+
+PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node )
+{
+    pj_list_insert_before(&parent->node_head, node);
+}
+
+PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr )
+{
+    pj_list_insert_before(&node->attr_head, attr);
+}
+
+PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name)
+{
+    pj_xml_node *node = parent->node_head.next;
+
+    PJ_CHECK_STACK();
+
+    while (node != (void*)&parent->node_head) {
+	if (pj_stricmp(&node->name, name) == 0)
+	    return node;
+	node = node->next;
+    }
+    return NULL;
+}
+
+
+PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node,
+					    const pj_str_t *name)
+{
+    PJ_CHECK_STACK();
+
+    node = node->next;
+    while (node != (void*)&parent->node_head) {
+	if (pj_stricmp(&node->name, name) == 0)
+	    return node;
+	node = node->next;
+    }
+    return NULL;
+}
+
+
+PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name,
+				       const pj_str_t *value)
+{
+    pj_xml_attr *attr = node->attr_head.next;
+    while (attr != (void*)&node->attr_head) {
+	if (pj_stricmp(&attr->name, name)==0) {
+	    if (value) {
+		if (pj_stricmp(&attr->value, value)==0)
+		    return attr;
+	    } else {
+		return attr;
+	    }
+	}
+	attr = attr->next;
+    }
+    return NULL;
+}
+
+
+
+PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,
+				  const void *data, 
+				  pj_bool_t (*match)(pj_xml_node *, const void*))
+{
+    pj_xml_node *head = (void*)&parent->node_head, *node = head->next;
+
+    while (node != (void*)head) {
+	if (name && pj_stricmp(&node->name, name)==0) {
+	    if (match) {
+		if (match(node, data))
+		    return node;
+	    } else {
+		return node;
+	    }
+	}
+	node = node->next;
+    }
+    return NULL;
+}
+